_alignof 返回类型的自然对齐值(2的幂),判断地址 ptr 是否对齐需用 reinterpret_cast(ptr) % _alignof(T) == 0;位运算 & (align - 1) 虽等价但不必要,且仅当对齐值为2的幂时安全。
怎么用
_alignof
判断一个类型是否对齐到指定地址
_alignof
返回的是类型的自然对齐要求(单位字节),不是运行时地址的对齐状态。它只能告诉你“这个类型希望被放在什么地址上”,不能直接告诉你“某个指针是否对齐”。常见错误是写成
if (_alignof(T) == addr % 8)
—— 这完全混淆了对齐要求和地址余数。
真正要判定地址
ptr
是否满足类型
T
的对齐要求,得用模运算检查地址值本身:
bool is_aligned(const void* ptr) {
return reinterpret_cast(ptr) % _alignof(T) == 0;
}
uintptr_t
是唯一能安全承载指针值的整数类型,别用
long
或
size_t
在跨平台时赌运气
模数必须是
_alignof(T)
,不是硬编码的 4/8/16;比如
std::max_align_t
在不同平台可能是 16 或 32
注意:
nullptr
的地址值是 0,0 对任何非零数取模都为 0,所以
is_aligned(nullptr)
会返回
true
,这符合标准但可能不符合业务逻辑,需额外判断
为什么不能直接用
addr & (align - 1)
替代
%
位运算是快,但前提是
align
必须是 2 的幂——而
_alignof
的结果**保证是 2 的幂**(C++11 起标准强制),所以这个优化是安全的。但很多人忽略了一个关键前提:对齐值必须已知为 2 的幂,否则
& (align - 1)
会得到错误结果。
例如,假设某编译器扩展支持
__attribute__((aligned(12)))
(12 不是 2 的幂),此时
_alignof
可能返回 12,那么
addr & 11
就不能等价于
addr % 12
。
立即学习
“
C++免费学习笔记(深入)
”;
C知道
CSDN推出的一款AI技术问答工具
下载
标准对齐(
_alignof
返回值)永远是 2 的幂,可放心用
& (align - 1)
自定义对齐(如
alignas(12)
)在 C++17 中若不是 2 的幂,会导致编译错误,所以实际不会出现
性能上,现代编译器对
% N
(N 为 2 的幂)会自动优化为位运算,手写
&
并不比
%
更优,还降低可读性
alignas
和
_alignof
的行为差异与陷阱
alignas
指定的是变量或类型的**最小对齐要求**,而
_alignof
返回的是该类型**实际生效的对齐值**。二者不一定相等:如果
alignas(2)
用在
int
上,而
int
默认对齐是 4,则
_alignof
仍返回 4。
alignas
的参数若小于自然对齐,会被忽略(除非显式使用
alignas(1)
强制取消对齐)
alignas(0)
是非法的,编译报错;
alignas(1)
是合法且有效的,表示“无需额外对齐”
结构体的
_alignof
不等于其成员最大
_alignof
,还受填充和最宽成员影响;例如
struct { char a; double b; }
的对齐通常为 8,但加
alignas(16)
后就变成 16
实战中容易漏掉的边界情况
内存对齐判定不是只在 malloc 后做一次就完事。真实场景里,偏移、切片、union 布局都会让地址偏离预期对齐位置。
用
char*
偏移后直接转成
int*
:即使原起始地址对齐,
ptr + 1
很可能就不满足
int
对齐了
结构体数组中,第 0 个元素对齐 ≠ 第 1 个元素对齐:若结构体大小不是其对齐值的倍数(如对齐 8、大小 12),则后续元素地址必然不对齐
std::vector
的数据指针不一定对齐到
_alignof(T)
:C++17 前无保证;C++17 起要求分配器满足对齐,但自定义分配器仍需手动确保
使用
std::aligned_storage
时,
alignof
返回的是存储类型本身的对齐(即你传入的值),不代表其中构造的对象自动获得该对齐——对象的实际对齐仍取决于其类型定义
对齐不是“设一次就稳了”的属性,它是地址、类型、布局三者动态作用的结果。每次把裸地址转成强类型指针前,都值得快速过一遍
reinterpret_cast(ptr) % _alignof(T)
。