【问题标题】:Memory alignment and size of structure内存对齐和结构大小
【发布时间】:2012-04-12 21:39:16
【问题描述】:
假设我定义了以下结构:
struct MyData {
int a;
char b;
int c;
byte d;
byte e;
}
我依稀记得读过该结构的大小不仅取决于数据类型,还取决于内存对齐方式。在 32 位 CPU 上,MyData 结构将是 4 字节 + 1 字节 + 4 字节 + 1 字节 + 1 字节 = 11 字节。这是我的问题,内存对齐是否会增加结构的大小:4 字节 + 1 字节(+3 字节填充)+ 4 字节 + 1 字节(+3 字节填充)+ 1 字节(+3 字节填充)= 20 字节。
这是错的吗?我错过了什么吗?这是特定于语言的东西吗?我可以打包结构吗?如果是这样,有什么优点和缺点?
谢谢!
【问题讨论】:
-
使用 sizeof() 进行一点谷歌搜索和测试可以为您提供大量信息。你可能会在这里找到一些有用的东西:c-faq.com
标签:
c
memory
memory-management
【解决方案1】:
编译器可以根据需要填充结构。通常,最后两个bytes 不会被填充分隔,因此大小将变为4 (int) + 1 (char) + 3 (padding) + 4 (int) + 1 (byte) + 1 (byte) + 2 (padding) = 16。
许多编译器允许根据编译指示打包结构。这样做的好处是内存使用较少,缺点是非对齐int 成员的读取速度较慢。
【解决方案2】:
您说内存对齐可以增加结构的大小并没有错;然而,任何关于如何对齐内存的猜测都不适用于所有平台。这完全是特定于平台的。
基本上,大多数平台倾向于在 ${WORDSIZE} 上对齐,或者如果数据类型小于 ${WORDSIZE},那么它会在 ${WORDSIZE} 的下一个可用部分上对齐
例如,如果您有一个 32 位字,并且您正在存储 16 位短片,它们可能会在一个字中的第 0 位和第 16 位对齐。但这不是保证,因为它确实是特定于平台的。
要调整结构以减少因填充造成的浪费,请按数据类型对元素进行排序,首先使用较大的数据类型。这倾向于允许将多个字节打包到同一个单词中(如果可能的话),并且大于单词的项将很好地终止于单词边界,因为它们往往是单词的干净倍数(四字,双字,...)
【解决方案3】:
结构成员之间和之后有未指定填充。第一个结构成员之前没有填充,即:
struct MyData bla;
int val = (char *) &bla == (char *) &bla.a; // val is 1
指向结构的指针(经过适当转换)指向第一个结构成员。
结构体对象的大小考虑了填充,等于成员大小之和+未指定填充大小之和。
【解决方案4】:
是的,编译器自然会在与其大小匹配的边界上对齐类型。您可以使用编译器编译指示强制结构打包,例如
#pragma pack(1)
您还可以通过重新排序声明以将 int 放在开头和之后的单个字节来避免一些填充。
您可以通过打印 sizeof(struct MyData) 来轻松测试这一点