There are multiple questions about the warning: dereferencing type-punned pointer might break strict-aliasing rules [-Wstrict-aliasing]
, from when adding compiler options -Wstrict-aliasing=2 -fstrict-aliasing
, and how to solve it.
For instance, the most upvoted answer to this Q states that,
(...) gcc assumes that your program will never access variables though pointers of different type. This assumption is called strict-aliasing and allows the compiler to make some optimizations (...)
When attempting to rewrite (read cast) a struct
as an array (for use in an external API), I found that the warning disapeared when adding an intermediate step of creating a pointer to said struct object, and casting that pointer instead.
I want to know if this is (not safe but) safer than directly casting the struct object's reference (which prompts the warning), or have I just conceiled what I'm doing from the compiler in such a way that the compiler doesn't see the danger and doesn't produce the warning? If it is safer, why? I don't really understand the actual difference.
If it matters, the reinterpret_cast
-ed data is never accessed: it is stored/transported and reinterpret_cast
-ed back again to the original struct
before being used.
#include <iostream>
#include <cstdint>
struct Container
{
uint32_t x;
uint32_t y;
};
// SomeApi could for instance have been (from <fcntl>),
// write(some_fd, data, size);
void SomeApi(uint32_t* data, size_t size)
{
for (size_t i=0; i<size; i++)
std::cout << (i==0?"{":", ") << static_cast<unsigned>(data[i]);
std::cout << "}\n";
}
int main() {
Container c{3,4};
uint32_t* data = reinterpret_cast<uint32_t*>(&c);
SomeApi(data, sizeof(c)/sizeof(uint32_t));
// warning: dereferencing type-punned pointer might break strict-aliasing rules [-Wstrict-aliasing]
Container* p_c = &c;
uint32_t* p_data = reinterpret_cast<uint32_t*>(p_c);
SomeApi(p_data, sizeof(c)/sizeof(uint32_t));
// Seemingly without issues?
return 0;
}
There is no difference, you have undefined behavior in the second loop iteration inside SomeApi
when you do static_cast<unsigned>(data[i])
with i == 1
because data[i]
will be the pointer one-past the object c.x
which, as all one-past pointers, musn't be dereferenced, which data[i]
however does.
Tricking the compiler's detection of the issue doesn't change anything about it.
Passing to write
instead of SomeApi
would be a different matter. Then you shouldn't doing any casting at all and the API is defined to access the underlying bytes of the object, not to access the object with a wrong type.