内存对齐是指按照与架构或数据类型相对应的特定字节数,将数据放置在内存中的地址上。正确的对齐对性能、硬件的正确操作以及某些CPU指令至关重要。
问题的历史。
在早期计算机中,未对齐会导致硬件故障(总线错误),而处理器的计算能力对非对齐的数据地址敏感。即使在现代架构中,正确的对齐也可以确保以1个时钟周期无惩罚地访问数据。
问题。
如果结构未考虑对齐,则读/写可能会变得更慢或无法执行(例如,在ARM或MIPS上崩溃)。此外,它还会影响低级API、设备的操作或数据的序列化以进行网络传输。
解决方案。
在C++中,有关键字alignas(C++11)和std::align来控制对齐,还有非标准的编译器属性(GCC/Clang中的__attribute__((aligned(N))),MSVC中的__declspec(align(N)))。
代码示例:
struct alignas(16) MyStruct { int a; double b; char c; }; #include <iostream> #include <type_traits> int main() { std::cout << alignof(MyStruct) << std::endl; // 16 std::cout << sizeof(MyStruct) << std::endl; }
关键特点:
结构成员声明的顺序是否会影响结构的大小和对齐?
是的,成员的顺序直接决定了它们之间的“填充”,这可能会在结构的大小中添加额外的字节。
struct S1 { char a; int b; }; // 通常sizeof==8(在4字节对齐下) struct S2 { int b; char a; }; // 通常sizeof==8,但有时填充更少
可以在不破坏对齐的情况下减少结构的大小吗?
可以,如果先将较大的成员分组,较小的成员放在后面。根据数据的位数有效地对齐:
struct S { double d; int i; char c; }; // 比零散放置更好
如果手动通过指针处理未对齐的地址,将会发生什么?
C++标准声明这样的行为为未定义行为(undefined behavior),某些CPU可能会引发SIGBUS或类似错误。
程序员实现了自己的结构来处理SIMD,但未指定对齐。因此,在某些ARM设备上尝试对未对齐的数据进行操作时,程序崩溃了。
优点:
缺点:
在处理视频数据(SSE/AVX)的项目中,应用了alignas用于缓冲结构,确保始终有效使用SIMD指令。
优点:
缺点: