我在char缓冲区中交换字节:
char* data; // some char buffer
uint16_t* data16 = reinterpret_cast<uint16_t*>(data);
// For debugging:
int align = reinterpret_cast<uintptr_t>(data) % alignof(uint16_t);
std::cout << "aligned? " << align << "\n";
for (size_t i = 0; i < length_of_data16; i++) {
#if defined(__GNUC__) || defined(__clang__)
data16[i] = __builtin_bswap16(data16[i]);
#elif defined(_MSC_VER)
data16[i] = _byteswap_ushort(data16[i]);
#endif
}
我从char*
投射到uint16_t*
,这会引发一面旗帜,因为它会投射到更严格对齐的类型。
但是,代码运行正常(在x86上),即使调试代码打印1(如同,未对齐)。在程序集中我看到MOVDQU
,我认为这意味着编译器认识到这可能没有对齐。
这与this question类似,答案是&#34;这不安全。&#34;以上代码是仅适用于某些体系结构和某些编译器,还是这两个问题之间存在细微差别,使上述代码有效?
(不太重要:与我在线阅读的内容一致,此代码的对齐和未对齐执行之间也没有明显的性能差异。)
答案 0 :(得分:1)
如果alignof(unit16_t) != 1
,则此行可能会因对齐而导致未定义的行为:
uint16_t* data16 = reinterpret_cast<uint16_t*>(data);
在之后进行对齐检查并不好;对于编译器,可以将检查硬编码为1
,因为它知道正确的代码无法达到该点。
在标准C ++中,为了使此检查有意义,它必须在强制转换之前发生,然后如果检查失败则不能执行强制转换。 (UB可以时间旅行)。
当然,个别编制者可能会选择定义未由标准定义的行为,例如也许g ++定位x86或x64包含一个定义,允许你形成未对齐的指针并取消引用它们。
没有严格的别名冲突,因为标准不涵盖__builtin_bswap16
,我们假设g ++以与自身一致的方式实现它。无论如何,MSVC都不会进行严格的别名优化。