struct A
{
char c;
double d;
} a;
sizeof a = 16
sizeof a = 12
为什么他们不同?我认为应该是16,gcc4.6.3会做一些优化吗?
答案 0 :(得分:11)
如果需要,编译器可以为目标体系结构执行数据结构对齐。它可能纯粹是为了提高应用程序的运行时性能,或者在某些情况下是处理器所要求的(即如果数据未对齐,程序将无法工作)。
例如,大多数(但不是全部)SSE2指令要求数据在16字节边界上对齐。简而言之,计算机内存中的所有内容都有一个地址。让我们说我们有一个简单的双打数组,如下所示:
double data[256];
为了使用需要16字节对齐的SSE2指令,必须确保&data[0]
的地址是16的倍数。
对齐要求因架构而异。在x86_64上,建议所有大于16字节的结构在16字节边界上对齐。通常,为获得最佳性能,请按如下方式对齐数据:
有趣的是,大多数x86_64 CPU都可以使用对齐和非对齐数据。但是,如果数据未正确对齐,则CPU执行代码的速度会慢得多。
当编译器考虑到这一点时,它可能会隐式地对齐结构的成员并且会影响其大小。例如,我们假设我们有这样的结构:
struct A {
char a;
int b;
};
假设x86_64,int
的大小为32位或4个字节。因此,建议始终将b
的地址设为4的倍数。但由于a
字段大小仅为1个字节,因此无法实现。因此,编译器会隐式地在a
和b
之间添加3个字节的填充:
struct A {
char a;
char __pad0[3]; /* This would be added by compiler,
without any field names - __pad0 is for
demonstration purposes */
int b;
};
编译器如何做到这一点不仅取决于编译器和体系结构,还取决于传递给编译器的编译器设置(标志)。使用特殊语言结构也会影响此行为。例如,可以要求编译器不执行任何具有packed
属性的填充,如下所示:
struct A {
char a;
int b;
} __attribute__((packed));
在您的情况下,mingw32-gcc.exe
只在c
和d
之间添加了7个字节,以便在8字节边界上对齐d
。而Ubuntu上的gcc 4.6.3仅在4字节边界上添加了3对齐d
。
除非您正在执行某些优化,尝试使用特殊的扩展指令集,或者对数据结构有特定要求,否则我建议您不依赖于特定的编译器行为,并且始终假设您的结构不仅可能得到填充,它可能会在架构,编译器和/或不同的编译器版本之间进行不同的填充。否则,您需要使用编译器属性和设置半手动确保数据对齐和结构大小,并确保它在所有使用单元测试或甚至static assertions定位的编译器和平台上都有效。< / p>
有关详细信息,请查看:
希望它有所帮助。祝你好运!
如何最小化填充:
让所有结构成员正确对齐并同时保持结构大小合理始终是件好事。考虑这两个结构变体,重新安排成员(从现在开始假设sizeof char,short,int,long,long long分别为1,2,4,4,8):
struct A
{
char a;
short b;
char c;
int d;
};
struct B
{
char a;
char c;
short b;
int d;
};
两个结构都应该保留相同的数据,但是当 sizeof(struct A)为12个字节时, sizeof(struct B)将是8个虽然out-out成员顺序消除了隐式填充:
struct A
{
char a;
char __pad0[1]; // implicit compiler padding
short b;
char c;
char __pad1[3]; // implicit compiler padding
int d;
};
struct B // no implicit padding
{
char a;
char c;
short b;
int d;
};
重新排列struct成员可能会因成员数增加而容易出错。为了减少错误 - 在开头放最长,在开头放最短:
struct B // no implicit padding
{
int d;
short b;
char a;
char c;
};
stuct结尾的隐式填充:
根据您使用的编译器,设置,平台等,您可能会注意到编译器不仅在结构成员之前添加填充,而且在结尾处(即在最后一个成员之后)添加填充。结构如下:
struct abcd
{
long long a;
char b;
};
可能占用12或16个字节(最差的编译器将允许它为9个字节)。这种填充可能很容易被忽视,但如果你的结构是阵列的话,这个非常重要。它将确保后续数组单元格/元素中的 成员也能正确对齐。
最终和随意的想法:
如果 - 在使用结构时 - 你会遵循这些建议,它永远不会伤害(并且实际上可能会保存):
答案 1 :(得分:7)
sizeof
为structs
返回的值不是任何C标准强制要求的。这取决于编译器和机器架构。
例如,在4字节边界上对齐数据成员可能是最佳的:在这种情况下,char c
的有效打包大小将为4个字节。