如何检查指针是否指向正确对齐的内存位置?

jot*_*tik 30 c++ memory-alignment c++11 c++14 c++17

给定void *一些存储,如何检查它是否指向正确对齐的存储而没有任何实现定义的行为?

我们当然有std::align,但是有更有效的方法吗?

template <std::size_t alignment>
inline bool is_aligned(void * ptr) noexcept {
    std::size_t max = 1u;
    return std::align(alignment, 1u, ptr, max);
}
Run Code Online (Sandbox Code Playgroud)

PS:我需要以兼容C++标准的方式执行此操作,而不依赖于任何特定于平台的(实现定义的)黑客攻击.

PPS:我为我(理解)英语而道歉,而不是我的母语.


EDIT(2018.08.24):从标题中删除了"有效",添加了更多的措辞,强调我不希望任何实现定义或特定于平台的行为.

eer*_*ika 20

如果在将地址与所需对齐分开时余数不为零,则地址不对齐.

inline bool
is_aligned(const void * ptr, std::uintptr_t alignment) noexcept {
    auto iptr = reinterpret_cast<std::uintptr_t>(ptr);
    return !(iptr % alignment);
}
Run Code Online (Sandbox Code Playgroud)

因为演员阵容,所以不能是constexpr.

此外,这依赖于实现定义的事实,即从指针到整数的转换必须保留地址的数字表示.正如评论所指出的那样,标准无法保证,因此该功能不一定能够移植到所有平台.这也是事实,因为它是可选的实现提供std::uintptr_t.


我希望在对齐类型时只需要这个,所以这可能更方便:

template<class T>
bool
is_aligned(const void * ptr) noexcept {
    auto iptr = reinterpret_cast<std::uintptr_t>(ptr);
    return !(iptr % alignof(T));
}
Run Code Online (Sandbox Code Playgroud)

  • 任何指针都可以转换为至少大小为"uintptr_t"的无符号整数.但是,结果是实现定义的.你假设使用了一个通用的实现,并且内存模型是平的,基本上,这很可能是现在,但不能保证. (3认同)
  • @ArneVogel是的,似乎不能保证严格可移植到模糊的平台,转换可能会改变对齐. (3认同)
  • @PhilArmstrong 2的补码不用于无符号数,它没有相关性:)但是,任何体面的优化器都能够进行转换. (2认同)
  • @PhilArmstrong我测试了你的功能,还测试了将constexpr添加到我的模板中.令我惊讶的是,这很有效.我很困惑,因为我不明白为什么reinterpret_cast可以在constexpr模板中使用,但不能在常规的constexpr函数中使用.你能解释/参考标准吗? (2认同)
  • @PhilArmstrong:没有模板参数满足所有`constexpr`要求的Constexpr函数模板格式错误,无需诊断.这就是你和@ user2079303所遇到的. (2认同)