为什么结构体的大小(sizeof)不等于其每个成员的大小(sizeof)之和?

21 浏览
0 Comments

为什么结构体的大小(sizeof)不等于其每个成员的大小(sizeof)之和?

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

admin 更改状态以发布 2023年5月23日
0
0 Comments

如C FAQ中所述,打包和字节对齐:

这是为了对齐。许多处理器无法访问2字节和4字节的变量(例如int和long int)如果它们被随意挤在一起。

假设您有此结构:

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  |
+-------+-------+-------+-------+

0
0 Comments

这是因为添加了填充以满足对齐约束条件。数据结构对齐 影响程序的性能和正确性:

  • 未对齐的访问可能是硬错误(通常为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语句来更改结构对齐设置。

0