为什么一个位字段的类型影响包含结构的大小? [英] Why would the type of a bit field affect the size of the containing structure?

查看:150
本文介绍了为什么一个位字段的类型影响包含结构的大小?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

首先,这里是ISO C标准说,大约位字段,引述 N1570 2011年的ISO C标准的草案,部分6.7.2.1:


  

一个位字段应具有一个类型,是一个合格的或不合格
  版本 _Bool 符号int unsigned int类型或其他
  实现定义的类型。这是实现定义是否
  原子类型是允许的。


...


  

一个位域间preTED为具有符号或无符号整型
  位组成的指定数字的。如果该值为0或1是
  存储类型的非零宽度位字段 _Bool 的价值
  位字段应比较等于存储的值;一个 _Bool
  位字段的语义 _Bool


  
  

这是实现可分配任何可寻址存储单元的大
  足以容纳一个比特字段。如果有足够的空间,一个位字段
  紧跟在一个结构的另一个位字段应装
  到相同单元的相邻比特。如果没有足够的空间仍然存在,
  不适合的位字段是否被放入下一个单元或
  重叠相邻单元是实现定义的。的顺序
  一个单位(高阶内位字段的分配低阶或
  低为高位)是实现定义的。的取向
  可寻址存储单元是不确定的。


对于任何结构键入,类型的对齐至少类型的任何成员的最大对齐,和任何类型的大小的倍数其对准。例如,如果一个结构包含一个(非位字段) INT 成员, INT 需要4个字节对准,则该结构本身需要4字节对齐或多个

_Bool 其他与 INT 类型整型的许多编译器许可位字段。

有关至少一些编译器,一个结构包含位字段是的声明类型的对位至少排列对齐领域。例如,对于在x86_64 GCC 4.7.2,给出:

 结构某人{
    _Bool BF:1;
};
结构SI {
    无符号BF:1;
};

GCC给结构SB 1个字节的大小和对齐(即 _Bool 的大小和排列)和结构SI 尺寸和4字节对齐(即 INT 的大小和排列)。它具有实现定义类型的位字段同样的事情;定义为 A位字段长长BF:1; 用于强制封闭结构的8字节大小和对齐。这样做,即使在两种情况下,位域 BF 是一个对象,其宽度只有1位。

我见过类似的行为与Sun的SPARC上/ Solaris中9。

编译

实验结果表明,多个位字段定义成 _Bool 无符号能装入内的相邻比特(在的需要的事实),所以位字段本身没有严格的对齐要求。单字节

据我所知,结构成员的布局主要是实现定义的,我不相信,海湾合作委员会的行为违反了C标准。

所以我的问题(的终于来了!的)是,为什么GCC做到这一点(至少有一个不相关的C编译器,可能更一起)?不要GCC的作者假定位字段声明的类型必须影响包含结构的大小和对齐?他们是在这个假设是正确的?有没有在C标准本身,我已经错过了一个要求吗?

下面是表现出行为的测试程序。如果你想你的系统上运行它,您可能需要注释掉它的部分,如果您使用的是旧的编译器不支持一些较新​​的功能,或一个不允许某些类型的位领域。如果有编译器不的行为与GCC做我有兴趣知道。

 的#include<&stdio.h中GT;
#包括LT&;&limits.h中GT;
#包括LT&;&stdint.h GT;
诠释主要(无效){
    结构某人{_Bool BF:1; };
    结构S8 {uint8_t有BF:1; };
    结构S16 {uint16_t BF:1; };
    结构S32 {uint32_t的BF:1; };
    结构S64 {uint64_t中BF:1; };
    的printf(的sizeof(结构SB)=%2zu(%2zu位)\\ n
           的sizeof(结构SB)
           的sizeof(结构某人)* CHAR_BIT);
    的printf(的sizeof(结构S8)=%2zu(%2zu位)\\ n
           的sizeof(结构S8)
           的sizeof(结构S8)* CHAR_BIT);
    的printf(的sizeof(结构S16)=%2zu(%2zu位)\\ n
           的sizeof(结构S16)
           的sizeof(结构S16)* CHAR_BIT);
    的printf(的sizeof(结构S32)=%2zu(%2zu位)\\ n
           的sizeof(结构S32),
           的sizeof(结构S32)* CHAR_BIT);
    的printf(的sizeof(结构S64)=%2zu(%2zu位)\\ n
           的sizeof(结构S64)
           的sizeof(结构S64)* CHAR_BIT);
    返回0;
}

下面是输出的,我得到我的系统上:

 的sizeof(结构某人)= 1(8位)
的sizeof(结构S8)= 1(8比特)
的sizeof(结构S16)= 2(16比特)
的sizeof(结构S32)= 4(32位)
的sizeof(结构S64)= 8(64位)


解决方案

在某种程度上你已经从标准这个引文自己回答了这个问题:


  的可寻址存储单元的排列是不确定的。


编译器可以选择任何调整,坚持以C标准,但是这并不是故事的全部。

为了为code。与不同的编译器进行互操作编制,平台ABI必须指定这些细节。例如,通过Linux x86上使用SYS-V的i386 ABI说:


  

位字段服从相同的大小
  和对准规则其他结构和联合件,具有以下
  补充:[...]


  
  

      
  • 位字段必须完全驻留在适合其宣称的存储单元
      类型。

  •   

然后,它遵循,无论宽度,一个位域必须位于东西是一个4字节边界上对齐。

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:

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.

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. 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.

Many compilers permit bit fields of integer types other than _Bool and the int types.

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. For example, for gcc 4.7.2 on x86_64, given:

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). It does the same thing with bit fields of implementation-defined types; a bit field defined as long long bf:1; forces an 8-byte size and alignment for the enclosing structure. This is done even though in both cases the bit field bf is an object whose width is just 1 bit.

I've seen similar behavior with Sun's compiler on SPARC/Solaris 9.

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.

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.

So my question (finally!) is, why does gcc (along with at least one unrelated C compiler, and probably more) do this? Do the authors of gcc assume that the declared type of a bit field must affect the size and alignment of the containing struct? Are they correct in this assumption? Is there a requirement in the C standard itself that I've missed?

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.

#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.

In order for code compiled with different compilers to interoperate, the platform ABI must specify these details. For example the SYS-V i386 ABI used by Linux x86 says:

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.

这篇关于为什么一个位字段的类型影响包含结构的大小?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆