为什么结构的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的空间。

