这是关于内存对齐的。在下面的代码中,我预计结构中b的偏移量为8(32位机器)。见here。在那里,使b
始终出现在缓存行中。但事实并非如此。 b
全局对象中的成员struct test1
似乎已对齐。我不确定它是偶然的还是编译器是故意这样做的。
我想了解为什么编译器在a
之后没有填充4个字节。
struct test1
{
int a;
double b;
}t1;
int main()
{
struct test1 *p = malloc(sizeof(struct test1));
printf("sizes int %d, float %d, double %d, long double %d\n", sizeof(int), sizeof(float), sizeof(double), sizeof(long double));
printf("offset of b %d\n",(int)&(t1.b)-(int)&(t1));
printf("\naddress of b (on heap) = %p, addr of b (on data seg) = %p\n",&(p->b), &(t1.b));
return 0;
}
输出是......
sizes int 4, float 4, double 8, long double 12
offset of b 4
address of b (on heap) = 0x804a07c, addr of b (on data seg) = 0x80497e0
我在ubuntu 10.04上使用标准的gcc编译器
答案 0 :(得分:5)
根据System V ABI for i386,第28页,double
只能获得4个字节的对齐,但建议编译器提供8个字节的选项。看来这是GCC在Linux上实现的,该选项被称为-malign-double
。
另一种方法是使用-m64
来获取x86-64目标代码,这在某些系统上已经是默认设置,包括Mac OS X.
答案 1 :(得分:4)
我预计结构中b的偏移量为8(32位机器)。见这里
您的参考资料解释了为什么8对齐双打可能有利。这并不等于保证,双精度始终是8对齐的。如果你的消息来源说他们总是8对齐,并且你观察到他们不是的实现,那么你的消息来源是错误的。
来自GCC手册页:
对齐 双字边界上的“双”变量将产生代码 奔腾上的运行速度稍慢,代价是更多的内存。
因此,GCC声明4对齐的原因是为了节省内存。您可以使用-malign-double
和-mno-align-double
来控制它,但是如果您在使用冲突选项编译的代码之间共享结构,那么您当然会面临创建二进制不兼容的风险。对于特定的对象/结构成员,您可以使用GCC自己的__attribute__((aligned))
,_Alignas
(在C11中)或alignas
(在C ++ 11中),所有这些都可以使用整数常量来指定所需的对齐。
答案 2 :(得分:0)
在ANSI C中根本无法保证对齐。
对齐自动变量比在堆上声明的任何内容更多。如果您使用的是POSIX OS,请使用memalign(3)接收您确定已对齐的内存。 Malloc可以在任何偏移处返回内存。您可以使用__attribute__ ((__packed__))
之类的编译器指令来放置自己的路线。