---
理论上:任何 2 的幂
alignas 的参数必须是 2 的幂(1, 2, 4, 8, 16, 32, 64, 128, 256, ...)。 不是 2 的幂,编译报错。
alignas(1) char c; // ✅ 1 字节对齐(默认就是这个)
alignas(2) short s; // ✅
alignas(4) int i; // ✅
alignas(8) long l; // ✅
alignas(16) float128_t f; // ✅ SSE 对齐
alignas(32) m256 v; // ✅ AVX 对齐
alignas(64) m512 w; // ✅ AVX-512 / 缓存行对齐
alignas(128) CacheLine2x x; // ✅ 两级缓存行(部分 ARM 平台)
alignas(256) BigBuffer b; // ✅ 256 字节对齐
alignas(4096) PageAligned p; // ✅ 页对齐(4KB 页)
alignas(1048576) HugePage h; // ✅ 大页对齐(1MB / 2MB)
alignas(3) int bad; // ❌ 编译错误,3 不是 2 的幂
alignas(0) int bad2; // ❌ 编译错误,0 不是 2 的幂
---
各典型值的场景
| 对齐值 | 典型用途 | 备注 |
|:------|:---------|:-----|
| 1 | 默认对齐(char) | 所有类型至少对齐到 1 |
| 2 | 16-bit 整数、UTF-16 | 很少显式写 |
| 4 | 32-bit 整数、float | 大多数平台的默认对齐 |
| 8 | 64-bit 指针、double | x86_64 指针默认 8 字节 |
| 16 | SSE 指令 (m128)、128-bit SIMD | 避免对齐惩罚 |
| 32 | AVX 指令 (m256) | |
| 64 | AVX-512、缓存行对齐、消除伪共享 | 最常用 |
| 128 | 部分 ARM 平台的二级缓存行 | 极少数场景 |
| 256~512 | GPU 共享内存、特殊 DMA | 嵌入式/汇编层 |
| 4096 | 页对齐(mmap / 大页 / O_DIRECT) | 非常重要 |
| 2M / 1G | 大页(HugeTLB) | 只在 mmap 或特殊分配器上用 |
---
实际限制
① 栈上大对齐不一定保证
void foo() {
alignas(4096) int buf[1024]; // ✅ 可以编译,但……
// 如果栈指针当前不在 4KB 边界上,编译器需要额外对齐
// 多数编译器通过 attribute((forcealignarg_pointer)) 处理
// 但对齐 > 16 字节时不敢 100% 保证所有调用路径都满足
}
安全经验:栈上对齐建议不超过 64 字节。超过 64 字节(尤其是 4096)最好用 std::aligned_alloc 放堆上。
② 堆上对齐
// C++17 起,alignas(128) 的类型的 new 会自动走 aligned new
auto* p = new MyAlignedType(); // ✅
// 手动分配任意对齐大小
void* buf = std::aligned_alloc(4096, 1024); // 4KB 对齐的 1KB 缓冲区
free(buf); // C11 风格,注意 C++ 中对应 std::free
// C++17 std::pmr 也可以用 aligned 分配器
③ 结构体的大对齐
struct alignas(4096) PageTableEntry {
// 整个结构体的 sizeof 会被补齐到 4096 的倍数
uint32_t data;
};
// sizeof(PageTableEntry) == 4096,不是 4
这通常不是你想要的效果——一个 4 字节的数据占了 4KB 内存。大对齐一般用在数组场景,而不是单个结构体。
更合理的用法:
// 只对齐 buffer,不浪费周边字段
struct IoBuffer {
int length;
alignas(4096) char data[4096]; // data 本身 4KB 对齐
};
④ 编译器支持上限
| 编译器 | 最大 alignas 值(典型) |
|:-------|:-----------------------|
| GCC | 2^32(但 > 2^16 实际无意义) |
| Clang | 同 GCC |
| MSVC | 2^16(65536),超出报错 |
实践中不会用到超过 2MB(大页大小)的对齐值。
---
常见误区
// ❌ 想对齐到 1MB,但 1MB = 1048576 是 2 的幂,语法合法
alignas(1048576) char huge[64]; // 编译通过,但栈上几乎必定 stack overflow
1MB 对齐 + 1MB 数组 ≈ 至少占 2MB 栈空间,线程默认栈大小通常只有 8MB,几个这样的变量就把栈撑爆了。
---
一句话总结
alignas 接受任何 2 的幂,从 1 到 2^32 都合法。 实际有用的是 16(SIMD)、64(缓存行)、4096(页对齐) 三个值。栈上用不超过 64,大对齐放堆上,否则编译器不一定保证、栈也可能撑爆。
发布评论