简体   繁体   English

为什么位字段的类型会影响包含结构的大小?

[英]Why would the type of a bit field affect the size of the containing structure?

First, here's what the ISO C standard says about bit fields, quoting the N1570 draft of the 2011 ISO C Standard, section 6.7.2.1: 首先,这是ISO C标准关于位域的内容,引用2011年ISO C标准的N1570草案,第6.7.2.1节:

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. 位字段的类型应为_Boolsigned intunsigned int或其他实现定义类型的限定或非限定版本。 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; 如果将值0或1存储到_Bool类型的非零宽度位字段中,则位字段的值应等于存储的值; a _Bool bit-field has the semantics of a _Bool . _Bool位字段具有_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. 未指定可寻址存储单元的对齐。

For any struct type, the alignment of the type is at least the maximum alignment of any member of the type, and the size of any type is a multiple of its alignment. 对于任何struct类型,类型的对齐方式至少是该类型的任何成员的最大对齐方式,并且任何类型的大小都是其对齐方式的倍数。 For example, if a structure contains a (non-bit-field) int member, and int requires 4-byte alignment, then the structure itself requires 4-byte alignment or more. 例如,如果结构包含(非位域) int成员,并且int需要4字节对齐,则结构本身需要4字节对齐或更多。

Many compilers permit bit fields of integer types other than _Bool and the int types. 许多编译器允许除_Boolint类型之外的整数类型的位字段。

For at least some compilers, the alignment of a struct containing a bit field is at least the alignment of the declared type of the bit field. 对于至少一些编译器,包含位字段的struct的对齐至少是声明的位字段类型的对齐。 For example, for gcc 4.7.2 on x86_64, given: 例如,对于x86_64上的gcc 4.7.2,给出:

struct sb {
    _Bool bf:1;
};
struct si {
    unsigned bf:1;
};

gcc gives struct sb a size and alignment of 1 byte (which is the size and alignment of _Bool ), and struct si a size and alignment of 4 bytes (which is the size and alignment of int ). gcc给struct sb一个大小和1个字节的对齐(这是_Bool的大小和对齐), struct si是一个大小和4个字节的对齐(这是int的大小和对齐)。 It does the same thing with bit fields of implementation-defined types; 它对实现定义类型的位字段做了同样的事情; a bit field defined as long long bf:1; 位字段定义为long long bf:1; forces an 8-byte size and alignment for the enclosing structure. 强制封闭结构的8字节大小和对齐。 This is done even though in both cases the bit field bf is an object whose width is just 1 bit. 即使在两种情况下,位字段bf是宽度仅为1位的对象,也可以完成此操作。

I've seen similar behavior with Sun's compiler on SPARC/Solaris 9. 我在SPARC / Solaris 9上看到了与Sun编译器类似的行为。

Experiment shows that multiple bit fields defined either as _Bool or as unsigned can be packed into adjacent bits within a single byte (in fact that's required), so the bit fields themselves do not have strict alignment requirements. 实验表明,定义为_Boolunsigned多个位字段可以打包到单个字节内的相邻位(实际上是必需的),因此位字段本身没有严格的对齐要求。

I understand that the layout of struct members is largely implementation-defined, and I don't believe that gcc's behavior violates the C standard. 我理解结构成员的布局主要是实现定义的,我不相信gcc的行为违反了C标准。

So my question ( finally! ) is, why does gcc (along with at least one unrelated C compiler, and probably more) do this? 所以我的问题( 最后! )是,为什么gcc(以及至少一个不相关的C编译器,可能还有更多)这样做? Do the authors of gcc assume that the declared type of a bit field must affect the size and alignment of the containing struct? gcc的作者是否认为声明的位字段类型必须影响包含结构的大小和对齐? Are they correct in this assumption? 它们在这个假设中是否正确? Is there a requirement in the C standard itself that I've missed? 我错过了C标准本身的要求吗?

Here's a test program that exhibits the behavior. 这是一个展示行为的测试程序。 If you want to run it on your system, you might need to comment out parts of it, if you're using an old compiler that doesn't support some of the newer features, or one that doesn't permit certain types of bit fields. 如果您想在系统上运行它,您可能需要注释掉它的一部分,如果您使用的是不支持某些较新功能的旧编译器,或者不允许某些类型的位领域。 I'd be interested in knowing if there are compilers that don't behave as gcc does. 如果有作为的行为确实GCC编译器我有兴趣知道。

#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)\n",
           sizeof (struct sb),
           sizeof (struct sb)  * CHAR_BIT);
    printf("sizeof (struct s8)  = %2zu (%2zu bits)\n",
           sizeof (struct s8),
           sizeof (struct s8)  * CHAR_BIT);
    printf("sizeof (struct s16) = %2zu (%2zu bits)\n",
           sizeof (struct s16),
           sizeof (struct s16) * CHAR_BIT);
    printf("sizeof (struct s32) = %2zu (%2zu bits)\n",
           sizeof (struct s32),
           sizeof (struct s32) * CHAR_BIT);
    printf("sizeof (struct s64) = %2zu (%2zu bits)\n",
           sizeof (struct s64),
           sizeof (struct s64) * CHAR_BIT);
    return 0;
}

Here's the output I get on my system: 这是我在我的系统上得到的输出:

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)

In a way you've answered the question yourself with this quotation from the standard: 在某种程度上,您已使用标准中的引用自行回答了问题:

The alignment of the addressable storage unit is unspecified. 未指定可寻址存储单元的对齐。

The compiler can choose any alignment and adhere to the C standard, but that's not the whole story. 编译器可以选择任何对齐并遵守C标准,但这不是全部。

In order for code compiled with different compilers to interoperate, the platform ABI must specify these details. 为了使用不同编译器编译的代码进行互操作,平台ABI必须指定这些细节。 For example the SYS-V i386 ABI used by Linux x86 says: 例如,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. 位字段必须完全驻留在适合其声明类型的存储单元中。

It then follows that regardless of the width, a long bitfield must reside in something that is aligned on a 4 byte boundary. 然后,无论宽度如何, long位域必须驻留在4字节边界上对齐的东西上。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM