gpt4 book ai didi

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

转载 作者:太空狗 更新时间:2023-10-29 17:11:55 25 4
gpt4 key购买 nike

首先,这是 ISO C 标准对位域的描述,引用了 N1570 2011 ISO C 标准草案,第 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.

对于任何struct类型,类型的对齐方式至少是该类型任何成员的最大对齐方式,任何类型的大小都是其对齐方式的倍数。例如,如果结构包含一个(非位域)int 成员,并且 int 需要 4 字节对齐,那么结构本身需要 4 字节对齐或更多。

许多编译器允许 _Boolint 类型以外的整数类型的位域。

至少对于某些编译器而言,包含位域的struct 的对齐方式至少是位域的声明类型 的对齐方式。例如,对于 x86_64 上的 gcc 4.7.2,给定:

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

gcc 给 struct sb 一个 1 字节的大小和对齐方式(这是 _Bool 的大小和对齐方式),而 struct si a 4 个字节的大小和对齐方式(即 int 的大小和对齐方式)。它对实现定义类型的位字段做同样的事情;定义为 long long bf:1; 的位字段强制使用 8 字节大小并对齐封闭结构。即使在这两种情况下,位域 bf 都是一个宽度仅为 1 位的对象,也是如此。

我在 SPARC/Solaris 9 上看到了 Sun 编译器的类似行为。

实验表明,定义为 _Boolunsigned 的多个位字段可以打包到单个字节内的相邻位中(事实上这是必需的),因此位字段本身没有严格的对齐要求。

我知道结构成员的布局主要是实现定义的,我不认为 gcc 的行为违反了 C 标准。

所以我的问题(最后!)是,为什么 gcc(以及至少一个不相关的 C 编译器,可能还有更多)这样做? gcc 的作者是否假定位字段的声明类型必须影响包含结构的大小和对齐方式?他们在这个假设中是否正确? C 标准本身是否有我遗漏的要求?

这是一个展示行为的测试程序。如果你想在你的系统上运行它,你可能需要注释掉它的一部分,如果你使用的是不支持某些新功能的旧编译器,或者不允许某些类型的位的编译器领域。我很想知道是否有编译器像 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;
}

这是我在系统上得到的输出:

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.

然后,无论宽度如何,long 位域必须驻留在与 4 字节边界对齐的内容中。

关于c - 为什么位字段的类型会影响包含结构的大小?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15980589/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com