This is a classical example of strict aliasing violation:
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);
}
But suppose we add the second 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);
}
Is this code correct (doesn't invoke undefined behaviour)?
The standard [expr.reinterpret.cast] reads:
Note: Converting a prvalue of type “pointer to
T1
” to the type “pointer toT2
” (whereT1
andT2
are object types and where the alignment requirements ofT2
are no stricter than those ofT1
) and back to its original type yields the original pointer value.
We use the original pointer value of type std::uint32_t*
to access the lvalue of type std::uint32_t
.
Both GCC and Clang generate correct assembly code when optimization is turned on:
foo(float*, unsigned int*):
mov dword ptr [rsi], 1
mov dword ptr [rdi], 2
mov eax, dword ptr [rsi]
ret