协慌网

登录 贡献 社区

为什么结构的 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语句以更改结构对齐设置。

包装和字节对齐,如在 C FAQ 描述在这里

这是为了对齐。如果很多处理器挤满了单向,那么它们将无法访问 2 字节和 4 字节的数量(例如,整数和长整数)。

假设您具有以下结构:

struct {
    char a[3];
    short int b;
    long int c;
    char d[3];
};

现在,您可能认为应该可以像下面这样将这种结构打包到内存中:

+-------+-------+-------+-------+
|           a           |   b   |
+-------+-------+-------+-------+
|   b   |           c           |
+-------+-------+-------+-------+
|   c   |           d           |
+-------+-------+-------+-------+

但是,如果编译器这样安排它,则在处理器上要容易得多:

+-------+-------+-------+
|           a           |
+-------+-------+-------+
|       b       |
+-------+-------+-------+-------+
|               c               |
+-------+-------+-------+-------+
|           d           |
+-------+-------+-------+

在压缩版中,请注意您对我和 b 和 c 字段如何环绕至少有点困难?简而言之,处理器也很难。因此,大多数编译器将像这样填充结构(好像带有额外的不可见字段):

+-------+-------+-------+-------+
|           a           | pad1  |
+-------+-------+-------+-------+
|       b       |     pad2      |
+-------+-------+-------+-------+
|               c               |
+-------+-------+-------+-------+
|           d           | pad3  |
+-------+-------+-------+-------+

例如,如果您希望结构在 GCC 中具有特定大小,请使用__attribute__((packed))

在 Windows 上,将 cl.exe 编译器与 / Zp 选项一起使用时,可以将对齐方式设置为一个字节。

通常,CPU 会更轻松地访问 4 或 8 的倍数的数据,具体取决于平台和编译器。

因此,这基本上是对齐的问题。

您需要有充分的理由进行更改。