考虑以下小程序,它使用联合直接分配整数的位而不是使用位操作。打印语句打印正确,但这并不意味着它始终有效。
这是在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和this question以及this question,但我仍然不确定。
答案 0 :(得分:4)
答案是代码将始终编译/运行(它感觉它是“标准”),但它不是“可移植的”,因为最后一行上的foo值无法保证。不同的编译器实现可以将位字段存储在存储器的不同位中,也就是说存储器foo引用。实际上,在考虑填充时,位字段可能甚至不会与foo完全重叠。
这是您链接到的第一个答案是试图说。
答案 1 :(得分:3)
可以将int
用于位字段。最好将signed int
用于位字段。更好的是使用unsigned
。这是int
和signed int
不同的地方(可能是唯一的地方)。 signed int xxx:1;
采用0或-1的值。 int xxx:1;
采用0 or 1
或 0 or -1
的值 - 它是实现定义的。
FooBar.bar.BIT31 = 1; // Highest order bit
不可移植,因为BIT31
可能是最不重要的位。代码依赖某个字节序。
在int/unsigned
宽度变化为16,32或64位的系统上,可移植性受到影响。
使用long BIT31:1;
或uint32_t BIT31:1;
可能无法移植,因为任何比int/unsigned
宽的位域都是实现定义的(或可能的UB)。
鉴于可能存在大量移植问题,强烈建议不要在可移植的代码段中使用位字段。
如果总位宽不是sizeof(unsigned)*CHAR_BIT
的倍数和/或字段尝试交叉对齐限制位宽,则可以预期填充。这通常是一个重大的复杂因素。
只有我使用位字段的地方是映射硬件寻址内存时,该部分代码需要有限的(如果有的话)可移植性。
结论:
使用联合中的位字段来解决32位
int
unsigned
是否定义明确?
一般没有。在特定应用程序中,通常是,当使用不会导致填充的unsigned
字段时。