为什么sizeof运算符返回的结构大小大于结构成员的总大小?


当前回答

C99 N1256标准草案

http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf

6.5.3.4操作员尺寸:

3当应用于具有结构或并集类型的操作数时,结果是这样的对象中的字节总数,包括内部和尾部衬垫。

6.7.2.1结构和接头规范:

13 ... 可能有未命名的在结构对象内填充,但不能在其开头填充。

and:

15在结构或联合体的末端可能有未命名的填充。

新的C99灵活数组成员特性(结构S{int is[];};)也可能影响填充:

16作为一种特殊情况,具有多个命名构件的结构的最后一个元素可以具有不完整的数组类型;这称为灵活阵列成员。在大多数情况下,柔性阵列成员被忽略。特别是,结构的大小似乎省略了灵活的数组成员,除了它可能具有比这一遗漏意味着。

附件J便携性问题重申:

以下未指定:。。。在结构或联合中存储值时填充字节的值(6.2.6.1)

C++11 N3337标准草案

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf

5.3.3尺寸:

2应用时对于类,结果是该类的对象中的字节数,包括将该类型的对象放置在数组中。

9.2班级成员:

指向标准布局结构对象的指针(使用reinterpret_cast进行适当转换)指向其初始成员(或者如果该成员是位字段,则返回到它所在的单元),反之亦然。[注:因此,在标准布局结构对象中可能存在未命名的填充,必要时实现适当的对齐。-尾注]

我只知道足够的C++来理解注释:-)

其他回答

如果隐式或显式设置了结构的对齐方式,则可以这样做。对齐为4的结构将始终是4字节的倍数,即使其成员的大小不是4字节的倍。

此外,一个库可以在x86下用32位int编译,并且您可以在64位进程上比较它的组件。如果您手动执行此操作,则会得到不同的结果。

打包和字节对齐,如C常见问题解答中所述:

这是为了对齐。许多处理器无法访问2字节和4字节数量(例如整数和长整数),如果它们被塞进每个方向。假设您有这样的结构:结构{字符a[3];短整数b;长整型c;字符d[3];};现在,你可能认为应该可以打包这个结构如下:+-------+-------+-------+-------+|a | b|+-------+-------+-------+-------+|b | c|+-------+-------+-------+-------+|c | d(c | d)|+-------+-------+-------+-------+但如果编译器安排,则处理器上的操作要简单得多它是这样的:+-------+-------+-------+|一个|+-------+-------+-------+|b级|+-------+-------+-------+-------+|c类|+-------+-------+-------+-------+|d)|+-------+-------+-------+在打包版本中,请注意,对于你和我想看看b和c字段是如何换行的?简而言之处理器也很难。因此,大多数编译器都会填充结构(好像有额外的、不可见的字段)如下:+-------+-------+-------+-------+|a |焊盘1|+-------+-------+-------+-------+|b |焊盘2|+-------+-------+-------+-------+|c类|+-------+-------+-------+-------+|d|焊盘3|+-------+-------+-------+-------+

这可能是由于字节对齐和填充,使得结构在您的平台上达到偶数字节(或单词)。例如,在Linux上的C中,以下3种结构:

#include "stdio.h"


struct oneInt {
  int x;
};

struct twoInts {
  int x;
  int y;
};

struct someBits {
  int x:2;
  int y:6;
};


int main (int argc, char** argv) {
  printf("oneInt=%zu\n",sizeof(struct oneInt));
  printf("twoInts=%zu\n",sizeof(struct twoInts));
  printf("someBits=%zu\n",sizeof(struct someBits));
  return 0;
}

成员的大小(以字节为单位)分别为4字节(32位)、8字节(2x 32位)和1字节(2+6位)。上面的程序(在使用gcc的Linux上)将大小打印为4、8和4,其中最后一个结构填充为一个单词(在我的32位平台上为4 x 8位字节)。

oneInt=4
twoInts=8
someBits=4

除了其他答案,结构可以(但通常不)具有虚拟函数,在这种情况下,结构的大小还将包括vtbl的空间。

C语言为编译器提供了一些关于内存中结构元素位置的自由:

内存孔可能出现在任意两个组件之间以及最后一个组件之后。这是由于目标计算机上的某些类型的对象可能受到寻址边界的限制sizeof运算符的结果中包含“内存孔”大小。sizeof仅不包括灵活数组的大小,灵活数组在C/C中可用++该语言的一些实现允许您通过pragma和编译器选项控制结构的内存布局

C语言为程序员提供了结构中元素布局的一些保证:

编译器需要分配一系列增加内存地址的组件第一个组件的地址与结构的起始地址一致未命名的位字段可以包括在结构中,以实现相邻元素的所需地址对齐

与元素对齐相关的问题:

不同的计算机以不同的方式排列对象的边缘位字段宽度的不同限制计算机在如何存储一个字中的字节方面存在差异(Intel 80x86和Motorola 68000)

对齐方式:

结构所占据的体积被计算为这样的结构阵列中对齐的单个元素的大小。结构应以便下一个后续结构的第一个元素不违反对齐要求

p.s更多详细信息可在此处获得:“塞缪尔·p·哈比森,盖伊·L·斯蒂尔C A参考,(5.6.2-5.6.7)”