写作时
struct {
unsigned a:3, b:2;
} x = {10, 11};
ANSI C(C89)保证x.b
为3
?我已阅读并重新阅读标准,但似乎无法找到确切的情况。
例如,“无法表示的结果 结果无符号整数类型以模数减少 一个大于可以表示的最大值 得到无符号整数类型。“谈论计算,而不是初始化。而且,位字段实际上不是一种类型。
另外,(当谈到无符号t:4时)“包含[0,15]范围内的值”,但这并不一定意味着初始化器必须减少模16 映射到[0,15]。
结构初始化真的是详细描述,但我似乎无法找到确切的行为。 (当然编译器就是这样做的。而且IBM文档说“当你将一个超出范围的值分配给一个位字段时,保留低位模式并分配适当的位。”,但我想要要知道ANSI C是否将其标准化。
答案 0 :(得分:5)
"ANSI C"/C89 has been obsolete for 25 years。因此,我的回答引用了当前的C标准ISO 9899:2011,也称为C11。
几乎所有与C标准中的位字段相关的内容都定义不明确。通常,您不会发现任何明确解决位字段行为的内容,但它们的行为是隐式指定的,“在行之间”。这就是你应该避免使用位字段的原因。
但是,我认为这个特定情况是明确定义的:它应该像任何其他整数初始化一样工作。
您提到的详细结构初始化规则(6.7.9)显示了初始化列表中的文字11
如何与变量b
相关联。没什么奇怪的。然后适用的是“简单分配”,就像你写x.b = 11;
时会发生的那样。
在C中进行任何类型的赋值或初始化时,右操作数转换为左操作数的类型。这由C11 6.5.16规定:
在简单赋值(=)中,转换右操作数的值 到赋值表达式的类型并替换存储的值 在左操作数指定的对象中。
在您的情况下, int 类型的文字11
将转换为 unsigned int:2 的位字段。
因此,您正在寻找的规则应该在涉及转换的章节中找到(C11 6.3)。适用的是您在问题中引用的内容,C11 6.3.1.3:
...如果新类型是无符号的,则重复转换该值 加或减一个可能的最大值 以新类型表示,直到值在新范围内 类型。
unsigned int:2 的最大值为3.比最大值多3 + 1 = 4。编译器应该重复从值11中减去它:
11 - (3+1) = 7 does not fit, subtract once more:
7 - (3+1) = 3 does fit, store value 3
但当然,这与取十进制值11的2个最低有效位并将它们存储在位域中是完全相同的。
答案 1 :(得分:2)
WRT"谈论计算,而不是关于初始化",C89标准明确地将赋值和转换规则应用于初始化。它还说:
位字段被解释为由指定位数组成的整数类型。
鉴于这些,虽然编译器警告显然是有序的,但标准保证丢弃高位比特。