使用联合内的位域来寻址 32 位“int”是否是明确定义的行为?

Is it well-defined behavior to address a 32-bit `int` using a bitfield inside a union?

考虑下面的小程序,它使用联合直接分配整数的位,而不是使用位操作。打印语句打印正确,但这并不意味着它总是有效。

这是 C 中明确定义的行为吗?

#include <stdio.h>
#include <inttypes.h>


union IntBitField{
    int32_t foo;

    struct bitfield {
        unsigned int BIT0:1;
        unsigned int BIT1:1;
        unsigned int BIT2:1;
        unsigned int BIT3:1;
        unsigned int BIT4:1;
        unsigned int BIT5:1;
        unsigned int BIT6:1;
        unsigned int BIT7:1;
        unsigned int BIT8:1;
        unsigned int BIT9:1;
        unsigned int BIT10:1;
        unsigned int BIT11:1;
        unsigned int BIT12:1;
        unsigned int BIT13:1;
        unsigned int BIT14:1;
        unsigned int BIT15:1;
        unsigned int BIT16:1;
        unsigned int BIT17:1;
        unsigned int BIT18:1;
        unsigned int BIT19:1;
        unsigned int BIT20:1;
        unsigned int BIT21:1;
        unsigned int BIT22:1;
        unsigned int BIT23:1;
        unsigned int BIT24:1;
        unsigned int BIT25:1;
        unsigned int BIT26:1;
        unsigned int BIT27:1;
        unsigned int BIT28:1;
        unsigned int BIT29:1;
        unsigned int BIT30:1;
        unsigned int BIT31:1;
    } bar;
} FooBar;
int main(){
    FooBar.foo = 0;
    printf("Size of the union: %zu\n", sizeof(union IntBitField));
    printf("Before setting any bits %"PRId32"\n", FooBar.foo);
    FooBar.bar.BIT31 = 1; // Highest order bit
    printf("Set BIT31 %"PRId32"\n", FooBar.foo);
}

我看过this question and this question, as well as this question,但我还是不确定。

答案是代码总是compile/run(从这个意义上说它是"standard"),但它不是"portable",因为最后一个foo的值线路不保证。不同的编译器实现可以将位字段存储在内存的不同位中,也就是说内存 foo 引用。事实上,在考虑填充时,位域甚至可能不会完全与 foo 重叠。

这就是您 link 想要表达的第一个答案。

  1. 位域用int就可以了。最好对位域使用 signed int。使用 unsigned 更好。这是 intsigned int 不同的地方(也许是唯一的地方)。 signed int xxx:1; 取值 0 或 -1。 int xxx:1; 采用 0 or 1 0 or -1 的值 - 它是实现定义的。

  2. FooBar.bar.BIT31 = 1; // Highest order bit 不可移植,因为 BIT31 可能是最低有效位。代码指望某个字节序。

  3. int/unsigned 宽度变化如 16、32 或 64 位的系统上,可移植性受到影响。

  4. 使用 long BIT31:1;uint32_t BIT31:1; 可能不可移植,因为任何比 int/unsigned 宽的位文件都是实现定义的(或可能的 UB)。

  5. 鉴于可能会出现大量移植问题,强烈建议不要将位域用于代码的可移植部分。

  6. 如果总位宽不是 sizeof(unsigned)*CHAR_BIT and/or 的倍数,则字段尝试交叉对齐限制位宽,可以预期填充。这通常是一个严重的并发症。

  7. 我唯一使用位字段的地方是在映射硬件寻址内存时,这部分代码需要限制(如果有的话)可移植性。

结论:

Is it well-defined behavior to address a 32-bit int unsigned using a bit field inside a union?

一般没有。在特定应用程序中,通常是,当使用 unsigned 不会导致填充的字段时。