包含位域的结构的大小

the size of a struct containing bitfields

我有一个struct如下。

struct A {
  uint32_t a : 1;
  uint32_t b : 1;
};

struct A 标准是否保证尺寸为 4?是否有可能用编译器代替 struct A 仅使用一个字节,因为它正好使用两位?

struct B {
  uint32_t a : 1;
  uint32_t b : 1;
  uint32_t c : 30;
} b;

如果我想将 b 中的位域设置为零,因为 sizeof(struct B) = 4,我觉得这样做很好 *(uint32_t*)&b = 0。但是我看到很多关于 SO 的讨论都认为这样的指针转换是一种不好的做法。我想知道是什么让 *(uint32_t*)&b = 0 变坏了,我应该怎么做(我知道我可以使用 memset 来重置位域,但我对其他可移植的方式很感兴趣)。

第一个问题,可以加个对齐,但是这样会影响执行效率:

#pragma pack(push)
#pragma pack(1)
struct A {
    uint32_t a : 1;
    uint32_t b : 1;
};
#pragma pack(pop)

第二个问题,可以定义成union

union B {
    struct {
        uint32_t a : 1;
        uint32_t b : 1;
        uint32_t c : 30;
    };
    uint32_t u;
} b;

// set the bitfields in b to zero
b.u = 0;

Is struct A guaranteed by the standard to have size 4?

没有。可能是 4 号,也可能不是。

Is it possible that a compiler instead uses only one byte for struct A since it uses exactly two bits?

是的,可能

I wonder what makes *(uint32_t*)&b = 0 bad here ...

  • 赋值可能不足以清零 b
  • 罕见:可选类型 uint32_t 可能不存在。
  • 代码存在别名问题。

... and what I should do

要将 b 归零,请分配一个 struct B 为零。研究复合文字。请注意,下面的代码适用于各种类型,而不仅仅是 structbit-fields.

b = (struct B){0};

或者,如果您想要一个 non-zero 值:

b = (struct B){.a = 0, .c = 42, .b = 1};

位域很棘手。使用 signed intunsigned int_Bool 而不是 uint32_t 以获得最大的可移植性。

A bit-field shall have a type that is a qualified or unqualified version of _Bool, signed int, unsigned int, or some other implementation-defined type. It is implementation-defined whether atomic types are permitted. C17dr § 6.7.2.1 5