Why would the type of a bit field affect the size of the containing structure?
首先,下面是ISO C标准对位字段的描述,引用2011 ISO C标准第6.7.2.1节的N1570草案:
A bit-field shall have a type that is a qualified or unqualified
version of_Bool ,signed int ,unsigned int , or some other
implementation-defined type. It is implementation-defined whether
atomic types are permitted.
…
A bit-field is interpreted as having a signed or unsigned integer type
consisting of the specified number of bits. If the value 0 or 1 is
stored into a nonzero-width bit-field of type_Bool , the value of
the bit-field shall compare equal to the value stored; a_Bool
bit-field has the semantics of a_Bool .An implementation may allocate any addressable storage unit large
enough to hold a bit- field. If enough space remains, a bit-field that
immediately follows another bit-field in a structure shall be packed
into adjacent bits of the same unit. If insufficient space remains,
whether a bit-field that does not fit is put into the next unit or
overlaps adjacent units is implementation-defined. The order of
allocation of bit-fields within a unit (high-order to low-order or
low-order to high-order) is implementation-defined. The alignment of
the addressable storage unit is unspecified.
对于任何
许多编译器允许除
对于至少一些编译器,包含位字段的
1 2 3 4 5 6 | struct sb { _Bool bf:1; }; struct si { unsigned bf:1; }; |
gcc给
我在sparc/solaris 9上看到过与Sun编译器类似的行为。
实验表明,定义为
我理解结构成员的布局很大程度上是由实现定义的,我不认为GCC的行为违反了C标准。
所以我的问题(终于!)是的,为什么GCC(以及至少一个不相关的C编译器,可能更多)会这样做?gcc的作者是否假定所声明的位字段类型必须影响包含结构的大小和对齐?他们在这个假设中是正确的吗?C标准本身是否有我遗漏的要求?
这是一个展示行为的测试程序。如果你想在你的系统上运行它,你可能需要注释掉它的某些部分,如果你使用的是一个不支持某些新特性的旧编译器,或者一个不允许某些类型的位域的编译器。我有兴趣知道是否有编译器的行为与GCC不同。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | #include <stdio.h> #include <limits.h> #include <stdint.h> int main(void) { struct sb { _Bool bf:1; }; struct s8 { uint8_t bf:1; }; struct s16 { uint16_t bf:1; }; struct s32 { uint32_t bf:1; }; struct s64 { uint64_t bf:1; }; printf("sizeof (struct sb) = %2zu (%2zu bits) ", sizeof (struct sb), sizeof (struct sb) * CHAR_BIT); printf("sizeof (struct s8) = %2zu (%2zu bits) ", sizeof (struct s8), sizeof (struct s8) * CHAR_BIT); printf("sizeof (struct s16) = %2zu (%2zu bits) ", sizeof (struct s16), sizeof (struct s16) * CHAR_BIT); printf("sizeof (struct s32) = %2zu (%2zu bits) ", sizeof (struct s32), sizeof (struct s32) * CHAR_BIT); printf("sizeof (struct s64) = %2zu (%2zu bits) ", sizeof (struct s64), sizeof (struct s64) * CHAR_BIT); return 0; } |
以下是我在系统上得到的输出:
1 2 3 4 5 | sizeof (struct sb) = 1 ( 8 bits) sizeof (struct s8) = 1 ( 8 bits) sizeof (struct s16) = 2 (16 bits) sizeof (struct s32) = 4 (32 bits) sizeof (struct s64) = 8 (64 bits) |
在某种程度上,你自己用标准中的引用回答了这个问题:
The alignment of the addressable storage unit is unspecified.
编译器可以选择任何对齐方式并遵循C标准,但这不是全部内容。
为了让用不同编译器编译的代码进行互操作,平台ABI必须指定这些详细信息。例如,Linux x86使用的sys-v i386 abi表示:
Bit-fields obey the same size
and alignment rules as other structure and union members, with the following
additions: [...]
- A bit-field must entirely reside in a storage unit appropriate for its declared
type.
然后,不管宽度如何,