【发布时间】:2020-03-31 14:12:22
【问题描述】:
这是一个 classical example 的严格别名违规:
std::uint32_t foo(float* f, std::uint32_t* i) {
*i = 1;
*f = 2;
return *i;
}
int main() {
std::uint32_t i = 3;
foo(reinterpret_cast<float*>(&i), &i);
}
但假设我们添加第二个reinterpret_cast:
static_assert(alignof(float) == alignof(std::uint32_t));
std::uint32_t foo(float* f, std::uint32_t* i) {
*i = 1;
*reinterpret_cast<std::uint32_t*>(f) = 2;
return *i;
}
int main() {
std::uint32_t i = 3;
std::uint32_t j = foo(reinterpret_cast<float*>(&i), &i);
assert(j == 2);
}
这段代码是否正确(不调用未定义的行为)?
标准[expr.reinterpret.cast]reads:
注意:将“指向
T1”的指针类型转换为“指向T2”的指针类型(其中T1和T2是对象类型,而T2的对齐要求不存在比T1) 更严格,并返回其原始类型会产生原始指针值。
我们使用std::uint32_t*类型的原始指针值来访问std::uint32_t类型的左值。
开启优化时,GCC 和 Clang 都会生成正确的汇编代码:
foo(float*, unsigned int*):
mov dword ptr [rsi], 1
mov dword ptr [rdi], 2
mov eax, dword ptr [rsi]
ret
【问题讨论】:
-
哦,该死的。我没有阅读所有代码。这实际上没问题,因为
f实际上确实指向uint32_t。评论已撤消。
标签: c++ language-lawyer reinterpret-cast strict-aliasing