sizeof(bitfield_type)在ANSI C中合法吗?
struct foo { unsigned x:1; } f; printf("%d\n", (int)sizeof(f.x = 1));
预期输出是什么?为什么?不允许直接采用位字段左值的大小。但是通过使用赋值运算符,似乎我们仍然可以获取位域类型的大小。
什么是"位域的大小(以字节为单位)"?它是保存位域的存储单元的大小吗? bf占用的位数是否舍入到最接近的字节数?
还是构造未定义的行为,因为标准中没有什么可以回答上述问题?同一平台上的多个编译器给我不一致的结果。
解决方案
回答
不会
(f.x = 1)
是一个评估为true的表达式(从技术上讲,是评估赋值的结果,在这种情况下为1 / true),因此,
sizeof( f.x = 1)
要求用存储多少个字符的形式来表示true的大小?
我还应该补充一点,有关sizeof的Wikipedia文章很好。特别是,他们说" sizeof是一个编译时运算符,它返回其前面的变量或者带括号的类型说明符的大小(以char的大小的倍数形式)。
本文还解释了sizeof可用于表达式。
回答
sizeof( f.x = 1)
返回1作为其答案。 sizeof(1)可能是我们要编译的平台上整数的大小,可能为4或者8个字节。
回答
不,我们必须考虑==运算符,该运算符在C中产生int类型的"布尔"表达式,在C ++中产生布尔值。
我认为该表达式会将值1转换为对应的位域类型,并将其分配给位域。结果也应该是位域类型,因为我看不到任何隐藏的促销或者转化。
因此,我们可以有效地访问位域类型。
不需要编译器诊断,因为" f.x = 1"不是左值,即它不直接指定位域。它只是" unsigned:1"类型的值。
我专门使用" f.x = 1",因为" sizeof f.x"采用位字段左值的大小,这显然是不允许的。
回答
如我们所见,试图获得位域的大小是不合法的。 (sizeof
返回以字节为单位的大小,这对于位域没有多大意义。)
sizeof(f.x = 1)将返回表达式类型的大小。由于C没有真正的"位域类型",因此表达式(此处为赋值表达式)通常获取位域基本类型的类型,在示例中是" unsigned int",但是编译器可以使用内部较小的类型(在这种情况下,可能是" unsigned char",因为它足以容纳一位)。
回答
这
(f.x = 1)
不是表达式,而是赋值,因此返回赋值。在这种情况下,该值的大小取决于已分配给该变量的变量。
unsigned x:1
有1位,其sizeof返回1个字节(8位对齐)
如果我们使用
unsigned x:12
那么sizeof(f.x = 1)将返回2个字节(同样由于8位对齐)
回答
The sizeof(1) is presumably the size of an integer on the platform you are compiling on, probably either 4 or 8 bytes.
请注意,我不使用sizeof(1),它实际上是sizeof(int)。仔细看,我正在使用sizeof(f.x = 1),它实际上应该是sizeof(bitfield_type)。
我希望看到对某些内容的引用,这些内容可以告诉我该结构是否合法。作为额外的好处,如果它告诉我期望什么样的结果,那将很好。
gcc当然不同意sizeof(bitfield_type)应该与sizeof(int)相同的主张,但仅在某些平台上才是如此。
回答
Trying to get the size of a bitfield isn't legal, as you have seen. (sizeof returns the size in bytes, which wouldn't make much sense for a bitfield.)
那么,我们是否声明该行为是不确定的,即与" *(int *)0 = 0;"具有相同的合法性,并且编译器可以选择不理智地处理此行为?
这就是我要找出的。我们是否认为它是由于遗漏而未定义的,或者是否有明确将其声明为非法的内容?
回答
is not an expression, it is an assignment and thus returns the assigned value. In this case, the size of that value depends on the variable, it has been assigned to.
首先,它是一个包含赋值运算符的表达式。
其次,我很清楚示例中发生的事情:)
then the sizeof(f.x = 1) would return 2 byte (again because of the 8 bit alignment)
你从哪儿得到的?这是在我们尝试过的特定编译器上发生的事情,还是这些语义在标准中说明?因为我还没有找到任何这样的陈述。我想知道该构造是否可以保证完全正常工作。
回答
在第二个示例中,如果我们将结构定义为
struct foo { unsigned x:12} f;
然后将诸如1的值写入f.x,由于对齐,它使用2个字节。如果我们做类似
f.x = 1;
并返回分配的值。这非常类似于
int a, b, c; a = b = c = 1;
从右到左评估赋值的位置。 c = 1为变量c分配1,并且该赋值返回赋值,并将其赋给b(依此类推),直到将1赋给a
它等于
a = ( b = ( c = 1 ) )
在情况下,sizeof获取分配的大小,它不是位域,而是分配给它的变量。
sizeof ( f.x = 1)
不会返回位字段的大小,但是变量asgment是1的12位表示形式(在我的情况下),因此sizeof()返回2个字节(由于8位分配)
回答
看,我完全理解我在做分配技巧。
我们正在告诉我,位域类型的大小被四舍五入为最接近的字节数,这是我在最初的问题中列出的一个选项。但是我们没有使用参考文献对其进行备份。
特别是,我尝试了各种编译器,即使我将其应用于只有一个位的位域,也可以给我sizeof(int)而不是sizeof(char)。
我什至不介意多个编译器随机地选择自己对此结构的解释。当然,位域存储分配是完全由实现定义的。
但是,我确实想知道该构造是否经过保证可以工作并产生一些价值。
回答
C99标准(最新草案的PDF)在6.5.3.4节中介绍了有关" sizeof"约束的内容:
The sizeof operator shall not be applied to an expression that has function type or an incomplete type, to the parenthesized name of such a type, or to an expression that designates a bit-field member.
这意味着允许将" sizeof"应用于赋值表达式。
6.5.16.3说:
The type of an assignment expression is the type of the left operand ...
6.3.1.1.2关于整数促销说:
The following may be used in an expression wherever an int or unsigned int may be used: ... A bit-field of type _Bool, int, signed int, or unsigned int. If an int can represent all values of the original type, the value is converted to an int; otherwise, it is converted to an unsigned int.
因此,测试程序应输出int
的大小,即
sizeof(int)。
是否有不符合此要求的编译器?
回答
CL,我之前看过引文,并同意它们是完全相关的,但是即使阅读了它们,我也不确定代码是否已定义。
6.3.1.1.2 says regarding integer promotions:
是的,但整数促销规则仅在实际上进行促销的情况下适用。我认为我的榜样不需要晋升。同样,如果你这样做
char ch; sizeof ch;
...那么ch也不会被提升。
我认为我们在这里直接处理位域类型。
我还看到了gcc输出1,而许多其他编译器(甚至其他gcc版本)却没有。这并不能使我确信代码是非法的,因为大小恰好可以实现定义,从而使结果在多个编译器中不一致。
但是,我对代码是否未定义感到困惑,因为标准中似乎没有任何内容说明如何处理sizeof位字段。
回答
没错,整数提升不适用于sizeof
的操作数:
The integer promotions are applied only: as part of the usual arithmetic conversions, to certain argument expressions, to the operands of the unary +, -, and ~ operators, and to both operands of the shift operators, as specified by their respective subclauses.
真正的问题是位域是否具有自己的类型。
约瑟夫·迈尔斯(Joseph Myers)告诉我:
The conclusion from C90 DRs was that bit-fields have their own types, and from C99 DRs was to leave whether they have their own types implementation-defined, and GCC follows the C90 DRs and so the assignment has type int:1 and is not promoted as an operand of sizeof.
缺陷报告#315中对此进行了讨论。
总结一下:代码是合法的,但是实现定义的。