5

コンパイル時にビットフィールドのマスクを見つけるための C での移植可能な方法はありますか?

理想的には、次のようなフィールドをアトミ​​ックにクリアできるようにしたいと考えています。

struct Reference {
    unsigned age : 3;
    unsigned marked : 1;
    unsigned references : 4;
};

struct Reference myRef;
__sync_and_and_fetch(&myRef, age, ~AGE_MASK);

それ以外の場合は、構造体のロックを解除する必要があります。これは、私が望むよりも重いものです。

4

5 に答える 5

2

次のようなことができます:

union Reference {
  unsigned asWord;
  struct {
    unsigned age : 3;
    unsigned marked : 1;
    unsigned references : 4;
  } asFields;
}

myRef のフィールドをアトミ​​ックにクリアするには、次のようにします。

union Reference myRef;

union Reference oldr = myRef;
union Reference newr = oldr;
newr.asFields.age = 0;
compare_and_swap(&myRef.asWord, oldr.asWord, newr.asWord);

(+ compare_and_swap が失敗したときに処理する未表示のコード)

于 2009-10-10T21:55:58.190 に答える
2

コンパイル時にそれを行う方法はわかりませんが、実行時には、ビットフィールド構造体のインスタンスを適切なサイズの unsigned int で結合し、作成したフィールド以外のすべてのフィールドを 0 に設定するだけで済みます。どれをすべて 1 に設定する必要があるかに注意してください。 unsigned int の値は、必要なビットマスクです。起動時に各フィールドに対して実行できます。おそらく、コードの繰り返しを避けるためにマクロを使用します。それで十分ではないでしょうか?

于 2009-10-10T21:56:18.203 に答える
2

または、本当にマスクが必要な場合:

union Reference {
  unsigned asWord;
  struct {
    unsigned age : 3;
    unsigned marked : 1;
    unsigned references : 4;
  } asFields;
}

Reference agemask_ref;
agemask_ref.asFields = (typeof(agemask_ref.asFields)){0, -1, -1};
unsigned agemask = agemask_ref.asWord;
于 2009-10-10T22:05:31.783 に答える
1

可能だとは思いません-バイトオフセットでは機能しますが、ビットフィールドでは機能しないように見えるoffsetof()を使用しても。フィールドを列挙型/定義 (0x01 0x02 など) として再宣言し、ビットを自分で管理して、アトミックな変更を取得できるようにします。

于 2009-10-10T21:54:44.757 に答える
0

はい、これは可能です。値を取得して操作を行う必要があります。次に、メモリにまだ古い値が含まれている場合は、アトミックな比較とスワップ (Windows の InterlockedCompareExchange など) を使用して新しい値を格納する必要があります。誰かが値を変更した場合は、ループして再試行します。これは、組み込み関数が使用できないワード サイズのデータ​​に対して任意の操作を実行するための標準的なパターンであることに注意してください。

以下のコードは int を使用しています - キースが指摘したように、共用体を使用して構造体の値を int として取得できます。

int oldValue, newValue;
do
{
    oldValue = myRef;
    newValue = oldValue & ~AGE_MASK;
} while (InterlockedCompareExchange(&myRef, newValue, oldValue) != oldValue);
于 2009-10-10T22:21:02.807 に答える