为啥结构的大小不等于其各个成员类型的大小之和? [复制]

Posted

技术标签:

【中文标题】为啥结构的大小不等于其各个成员类型的大小之和? [复制]【英文标题】:Why doesn't size of struct is equals to sum of sizes of its individual member types? [duplicate]为什么结构的大小不等于其各个成员类型的大小之和? [复制] 【发布时间】:2011-03-22 22:45:25 【问题描述】:

可能重复:Why isn’t sizeof for a struct equal to the sum of sizeof of each member?

我想以前一定有人在 SO 上问过类似(重复)的问题。但我找不到它们。基本上我不知道要搜索什么。所以在这里问。

为什么结构的大小不等于其各个成员类型的大小之和? 我正在使用可视化 C++ 编译器。

例如,假设是 32 位机器。 => sizeof(int) == 4; sizeof(char) == 1; sizeof(short) == 2;

  struct 
      int k;
      char c;
   s;

预期大小为 4+1 = 5;但 sizeof(s) 给出 8。这里 char 占用 4 个字节而不是 1。我不知道确切原因,但我的猜测是编译器这样做是为了提高效率。

struct
 long long k;
 int i;
 s;

预期大小为 4+4 = 8(在 32 位机器上)和 8+4=12(在 64 位机器上)。但奇怪的是 sizeof(s) 给出 16。这里 int 和 long long 都占用 8 个字节。

    这东西叫什么? 到底发生了什么? 为什么编译器会这样做? 有没有办法告诉编译器停止这样做?

【问题讨论】:

重复Why isn't sizeof for a struct equal to the sum of sizeof of each member? 第一次。投票结束我自己的问题。 :) 旁注:sizeof(long long) 在任何机器上都必须是 64 位的,因为它必须代表正负 (2^63 - 1) en.wikipedia.org/wiki/Data_structure_alignment 【参考方案1】:

这是因为编译器使用填充将每个元素带入特定于您正在编译的体系结构的字对齐。

这可能是几个原因之一,但通常是:

    因为某些 CPU 根本无法读取 long 或 long long 多字节值,当它不在其自身大小倍数的地址上时。

    因为可以读取未对齐数据的 CPU 的读取速度可能比对齐时慢得多。

您通常可以使用特定于编译器的指令或编译指示强制关闭它。

当您这样做时,编译器将生成相对低效的代码来使用多个读/写操作访问未对齐的数据。

【讨论】:

CPU's simply cannot read a multi-byte value。你能举几个这样的CPU的例子吗?为什么他们不能读取多字节值,除非它不在其自身大小的倍数的地址上?我的意思是,neath 下到底发生了什么? word alignment that is specific to the architecture那么,每个架构都指定字对齐值?我通常可以在架构的说明手册中的哪个部分找到它们? 一个例子是 ARM 架构。另一个是 MIPS。他们的行为有些不同。如果您尝试从 ARM 上的地址 0x000000005 读取长字(32 位),它实际上会从地址 0x00000004 读取它并给您错误的值。在 MIPS 上,您可能会遇到内存错误/异常。具体要求在它们各自的指令集架构手册中有很好的描述,但我不能直接从内存中引用确切的部分。至于为什么,它们是低门数 RISC CPU,根本没有硬件来调整总线通道来给你结果。【参考方案2】:

编译器可以在成员之间或结构末尾插入填充。通常在成员之间进行填充以保持成员对齐以最大化访问速度。最后填充的原因大致相同,以防您决定创建一个结构数组。

为防止这种情况发生,您可以使用 #pragma pack(1) 之类的内容。

【讨论】:

【参考方案3】:

这称为填充;这涉及添加更多字节,以便在可被某些特殊数字(通常为 2、4 或 8)整除的地址上对齐结构。编译器甚至可以在成员之间放置填充,以在这些边界上对齐字段本身。

这是一种性能优化:访问对齐的内存地址更快,有些架构甚至不支持访问未对齐的地址。

对于 VC++,您可以使用pack pragma 来控制字段之间的填充。但是请注意,不同的编译器有不同的处理方式,因此,例如,如果您还想支持 GCC,则必须为此使用不同的声明。

【讨论】:

+1 感谢您解释控制是特定于编译器的。但我真的不喜欢人们只留下剩下的 2% 的信息并停止使其完整。请添加 GCC 使用的内容以使其完整。 @claws:据我所知,在结束结构的 之后放置 __attribute__((__packed__)); 应该这样做 - 但我自己从未尝试过使用 GCC(或 VS,为此问题),据我所知,也可能有其他方法。当然,这仍然不完整,因为还有其他编译器,例如 Borland/CodeGear/Embarcadero C++(我什至 less 知道该怎么做它在那里)。

以上是关于为啥结构的大小不等于其各个成员类型的大小之和? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

C语言中结构体变量所占内存大小的计算

结构体struct和联合体union(联合)有啥区别呢?

结构体变量字节填充

位段的使用

关于位域在结构体的应用

为啥固定大小的缓冲区只能是原始类型?