C 中的位域掩码

发布于 2024-08-07 20:17:32 字数 301 浏览 2 评论 0原文

C 中是否有一种可移植的方法可以在编译时找出位字段的掩码?

理想情况下,我希望能够以原子方式清除这样的字段:

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

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

否则我必须取出结构上的锁,这比我想要的更重量级。

Is there a portable way in C to find out the mask for a bit field at compile time?

Ideally, I'd like to be able to atomically clear a field like this:

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

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

Otherwise I have to take out a lock on the struct, which is more heavyweight than I'd like.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

孤者何惧 2024-08-14 20:17:32

或者,如果你真的想要面具:

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;

Or, if you really wanted the mask:

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;
盛装女皇 2024-08-14 20:17:32

您可以执行以下操作:

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 失败时要处理的未显示代码)

You could do something like:

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

To atomically clear a field of myRef, do

union Reference myRef;

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

(+ unshown code to handle when compare_and_swap fails)

蒗幽 2024-08-14 20:17:32

我不知道如何在编译时执行此操作,但在运行时,将位域结构的实例与适当大小的无符号整数联合起来应该是一个简单的问题,并将除您之外的所有字段设置为 0关心哪个应该设置为全 1——unsigned int 的值就是您想要的位掩码。您可以在启动时为每个字段执行此操作,也许可以使用宏来避免一些重复的代码。也许这还不够?

I don't know how to do it at compile time, but at runtime it should be a simple matter of union'ing an instance of your bitfield struct with an appropriately-sized unsigned int, and setting all fields to 0 except the one you care about which should be set to all 1s -- the value of the unsigned int is then the bitmask you want. You can do it for each field at startup, maybe with a macro to avoid some repetitive code. Might not that suffice?

要走干脆点 2024-08-14 20:17:32

我认为这是不可能的 - 即使使用 offsetof() ,它适用于字节偏移,但似乎不适用于位字段。我会将这些字段重新声明为枚举/定义(0x01 0x02 等)并自己管理这些位,这样您就可以获得原子更改。

I don't think is possible - even with offsetof() which works for byte offsets but does not seem to work for bitfields. I would redeclare the fields as enums/defines (0x01 0x02 etc) and manage the bits yourself, so you can get your atomic changes.

风和你 2024-08-14 20:17:32

是的,这是可以做到的。您需要捕获该值并进行操作。然后,如果内存仍然包含旧值,则需要使用原子比较和交换(如 Windows 上的 InterlockedCompareExchange)来存储新值。如果有人修改了该值,您将循环并重试。请注意,这是一种标准模式,用于在内部函数不可用的情况下对字大小的数据进行任何操作。

下面的代码使用 int - 正如 Keith 指出的那样,您可以使用 union 来获取结构体的值作为 int。

int oldValue, newValue;
do
{
    oldValue = myRef;
    newValue = oldValue & ~AGE_MASK;
} while (InterlockedCompareExchange(&myRef, newValue, oldValue) != oldValue);

Yes, this can be done. You need to capture the value and do the operation. Then you need to use an atomic compare and swap (like InterlockedCompareExchange on Windows) to store the new value if the memory still contains the old value. If someone modified the value, you loop and try again. Note this is a standard pattern for doing any operation on a word-sized piece of data where an intrinsic isn't available.

The code below uses an int - as Keith pointed out you can use a union to be able to get the values of the struct as an int.

int oldValue, newValue;
do
{
    oldValue = myRef;
    newValue = oldValue & ~AGE_MASK;
} while (InterlockedCompareExchange(&myRef, newValue, oldValue) != oldValue);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文