为什么结构的sizeof不等于每个成员的sizeof之和?
为什么'sizeof'运算符返回的结构尺寸大于结构成员的总尺寸?
解决方案
这是因为添加了填充以满足对齐约束。数据结构对齐会影响程序的性能和正确性:
- 对齐错误的访问可能是一个硬错误(通常是SIGBUS)。
- 或者通过软件仿真进行纠正,以免导致性能严重下降。
- 此外,原子性和其他并发保证可能会被破坏,从而导致细微的错误。
这是一个使用x86处理器的典型设置的示例(所有使用的32位和64位模式):
struct X { short s; /* 2 bytes */ /* 2 padding bytes */ int i; /* 4 bytes */ char c; /* 1 byte */ /* 3 padding bytes */ }; struct Y { int i; /* 4 bytes */ char c; /* 1 byte */ /* 1 padding byte */ short s; /* 2 bytes */ }; struct Z { int i; /* 4 bytes */ short s; /* 2 bytes */ char c; /* 1 byte */ /* 1 padding byte */ }; const int sizeX = sizeof(struct X); /* = 12 */ const int sizeY = sizeof(struct Y); /* = 8 */ const int sizeZ = sizeof(struct Z); /* = 8 */
通过按对齐方式对成员排序(按基本类型中的大小进行排序)可以使结构的大小最小化(就像上面示例中的结构" Z"一样)。
重要说明:C和C ++标准均声明结构对齐方式是实现定义的。因此,每个编译器可能选择不同地对齐数据,从而导致不同且不兼容的数据布局。因此,在处理将由不同编译器使用的库时,重要的是要了解编译器如何对齐数据。一些编译器具有命令行设置和/或者特殊的#pragma语句来更改结构对齐设置。
如果我们隐式或者显式设置了结构的对齐方式,则可以这样做。对齐4的结构将始终是4字节的倍数,即使其成员的大小不是4字节的倍数也是如此。
同样,库可能会在x86下使用32位int进行编译,并且我们可能在64位进程中比较其组件,如果我们手动执行此操作,则会得到不同的结果。
打包和字节对齐,如此处的C常见问题解答所述:
It's for alignment. Many processors can't access 2- and 4-byte quantities (e.g. ints and long ints) if they're crammed in every-which-way. Suppose you have this structure: struct { char a[3]; short int b; long int c; char d[3]; }; Now, you might think that it ought to be possible to pack this structure into memory like this: +-------+-------+-------+-------+ | a | b | +-------+-------+-------+-------+ | b | c | +-------+-------+-------+-------+ | c | d | +-------+-------+-------+-------+ But it's much, much easier on the processor if the compiler arranges it like this: +-------+-------+-------+ | a | +-------+-------+-------+ | b | +-------+-------+-------+-------+ | c | +-------+-------+-------+-------+ | d | +-------+-------+-------+ In the packed version, notice how it's at least a little bit hard for you and me to see how the b and c fields wrap around? In a nutshell, it's hard for the processor, too. Therefore, most compilers will pad the structure (as if with extra, invisible fields) like this: +-------+-------+-------+-------+ | a | pad1 | +-------+-------+-------+-------+ | b | pad2 | +-------+-------+-------+-------+ | c | +-------+-------+-------+-------+ | d | pad3 | +-------+-------+-------+-------+
这可能是由于字节对齐和填充所致,因此该结构在平台上显示为偶数个字节(或者字)。例如,在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
例如,如果我们希望结构在GCC中具有特定大小,请使用____ attribute __((packed))`。
在Windows上,将cl.exe编译器与/ Zp选项一起使用时,可以将对齐方式设置为一个字节。
通常,CPU会更轻松地访问4或者8的倍数的数据,具体取决于平台和编译器。
因此,这基本上是对齐的问题。
我们需要有充分的理由进行更改。
除了其他答案外,结构可以(但通常没有)具有虚函数,在这种情况下,结构的大小还将包括vtbl的空间。