这是关于内存中基元类型的数据对齐的书。
Microsoft Windows强加了一个更强的对齐要求 - 任何K字节的原始对象,用于 K = 2,4或8,必须具有K的倍数的地址。特别地,它需要地址 一个double或long long是8的倍数。这个要求增强了内存性能 一些浪费空间的代价。 Linux约定,其中8字节值以4字节对齐 对于i386来说边界可能是好的,当内存稀缺和内存接口时,它就会回来 只有4个字节宽。使用现代处理器,微软的一致性是一个更好的设计决策。数据类型 long double,gcc生成IA32代码,分配12个字节(即使实际数据类型 只需10个字节)对Windows和Linux都有4字节对齐要求。
问题是:
答案 0 :(得分:3)
一般来说,编译器会强制对齐。无论何时声明基本类型(例如double
),编译器都会自动将其对齐到堆栈上的8个字节。
此外,内存分配通常也与最大的基本类型对齐,以便您可以安全地执行此操作:
double *ptr = (double*)malloc(size);
无需担心对齐。
因此,一般来说,如果你有良好的习惯编程,你就不必担心对齐。弄错的一种方法是做这样的事情:
char *ch_ptr = (char*)malloc(size);
double *d_ptr = (double*)(ch_ptr + 1);
这个有一些例外:当你开始进入SSE和矢量化时,事情变得有点乱,因为malloc
不再保证16字节对齐。
要覆盖某些内容的对齐方式,MSVC会使用declspec(align)
修饰符来允许此操作。它习惯于增加某事物的对齐方式。 虽然我不确定它是否允许你减少原始类型的对齐。它明确表示你不能减少与这个修饰符的对齐。
编辑:
我发现文档说明malloc()
在GCC上的对齐方式:
GNU系统中malloc或realloc返回的块的地址 总是8的倍数(或64位系统上的16)。
来源:http://www.gnu.org/s/hello/manual/libc/Aligned-Memory-Blocks.html
所以是的,GCC现在至少对齐8个字节。
答案 1 :(得分:3)
x86 CPU的对齐要求非常宽松。大多数数据可以在未对齐的位置存储和访问,可能以降低性能为代价。当您开始开发多处理器软件时,事情变得更加复杂,因为对齐对于原子性和观察到的事件顺序变得很重要(从内存写入,这可能不完全正确)。
编译器通常可以指向与默认对齐方式不同的变量。有针对该特定编译器和特殊编译器特定关键字的编译器选项(例如#pragma pack
和其他)。
既不能由应用程序员(操作系统已经编译),也不能由操作系统开发人员更改成熟的OS API(当然,除非它们能够破坏兼容性)。
所以,你可以改变一些事情,但不是一切。
答案 2 :(得分:0)
我不知道微软从哪里获取信息,但结果如何 gcc(4.6.1目标:x86_64-linux-gnu,标准模式,除了-Wall之外没有标志)是完全不同的:
#include <stdio.h>
struct lll {
long l;
long long ll;
};
struct lld {
long l;
long double ld;
};
struct lll lll1, lll2[2];
struct lld lld1, lld2[2];
int main(void)
{
printf("lll1=%u, lll2=%u\n"
, (unsigned) sizeof lll1
, (unsigned) sizeof lll2
);
printf("lld=%u, lld2=%u\n"
, (unsigned) sizeof lld1
, (unsigned) sizeof lld2
);
return 0;
}
结果:
./a.out
lll1=16, lll2=32
lld=32, lld2=64
这可能是FUD(来自实际设法将未对齐的整数投入MBR的公司......)。但这也可能是由于作者没有得到太多的了解。
回答这个问题:施加对齐限制的硬件。编译器只需要实现它们。