是否使用联盟内的位域来解决32位`int`的定义明确的行为?

时间:2016-03-03 01:08:00

标签: c gcc language-lawyer unions bit-fields

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

这是在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 questionthis question以及this question,但我仍然不确定。

2 个答案:

答案 0 :(得分:4)

答案是代码将始终编译/运行(它感觉它是“标准”),但它不是“可移植的”,因为最后一行上的foo值无法保证。不同的编译器实现可以将位字段存储在存储器的不同位中,也就是说存储器foo引用。实际上,在考虑填充时,位字段可能甚至不会与foo完全重叠。

这是您链接到的第一个答案是试图说。

答案 1 :(得分:3)

  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的倍数和/或字段尝试交叉对齐限制位宽,则可以预期填充。这通常是一个重大的复杂因素。

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

  8. 结论:

      

    使用联合中的位字段来解决32位 int unsigned是否定义明确?

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