使用联合内的位域来寻址 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 想要表达的第一个答案。
位域用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
and/or 的倍数,则字段尝试交叉对齐限制位宽,可以预期填充。这通常是一个严重的并发症。
我唯一使用位字段的地方是在映射硬件寻址内存时,这部分代码需要限制(如果有的话)可移植性。
结论:
Is it well-defined behavior to address a 32-bit int
unsigned
using a bit field inside a union?
一般没有。在特定应用程序中,通常是,当使用 unsigned
不会导致填充的字段时。
考虑下面的小程序,它使用联合直接分配整数的位,而不是使用位操作。打印语句打印正确,但这并不意味着它总是有效。
这是 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 想要表达的第一个答案。
位域用
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
and/or 的倍数,则字段尝试交叉对齐限制位宽,可以预期填充。这通常是一个严重的并发症。我唯一使用位字段的地方是在映射硬件寻址内存时,这部分代码需要限制(如果有的话)可移植性。
结论:
Is it well-defined behavior to address a 32-bit
int
unsigned
using a bit field inside a union?
一般没有。在特定应用程序中,通常是,当使用 unsigned
不会导致填充的字段时。