初始化位域

时间:2014-05-12 12:28:02

标签: c struct initialization ansi bit-fields

写作时

struct {
    unsigned a:3, b:2;
} x = {10, 11};
ANSI C(C89)

保证x.b3?我已阅读并重新阅读标准,但似乎无法找到确切的情况。

例如,“无法表示的结果 结果无符号整数类型以模数减少 一个大于可以表示的最大值 得到无符号整数类型。“谈论计算,而不是初始化。而且,位字段实际上不是一种类型。

另外,(当谈到无符号t:4时)“包含[0,15]范围内的值”,但这并不一定意味着初始化器必须减少模16 映射到[0,15]。

结构初始化真的是详细描述,但我似乎无法找到确切的行为。 (当然编译器就是这样做的。而且IBM文档说“当你将一个超出范围的值分配给一个位字段时,保留低位模式并分配适当的位。”,但我想要要知道ANSI C是否将其标准化。

2 个答案:

答案 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标准明确地将赋值和转换规则应用于初始化。它还说:

  

位字段被解释为由指定位数组成的整数类型。

鉴于这些,虽然编译器警告显然是有序的,但标准保证丢弃高位比特。