I’m curious about conventions for type-punning pointers/arrays in C++. Here’s the use case I have at the moment:
Compute a simple 32-bit checksum over a binary blob of data by treating it as an array of 32-bit integers (we know its total length is a multiple of 4), and then summing up all values and ignoring overflow.
I would expect such an function to look like this:
uint32_t compute_checksum(const char *data, size_t size) { const uint32_t *udata = /* ??? */; uint32_t checksum = 0; for (size_t i = 0; i != size / 4; ++i) checksum += udata[i]; return udata; }
Now the question I have is, what do you consider the ‘best’ way to convert data to udata?
C-style cast?
udata = (const uint32_t *)data
C++ cast that assumes all pointers are convertible?
udata = reinterpret_cast<const uint32_t *>(data)
C++ cast that between arbitrary pointer types using intermediate void*?
udata = static_cast<const uint32_t *>(static_cast<const void *>(data))
Cast through a union?
union { const uint32_t *udata; const char *cdata; }; cdata = data; // now use udata
I fully realize that this will not be a 100% portable solution, but I am only expecting to use it on a small set of platforms where I know it works (namely unaligned memory accesses and compiler assumptions on pointer aliasing). What would you recommend?
As far as the C++ standard is concerned, litb‘s answer is completely correct and the most portable. Casting
const char *datato aconst uint3_t *, whether it be via a C-style cast,static_cast, orreinterpret_cast, breaks the strict aliasing rules (see Understanding Strict Aliasing). If you compile with full optimization, there’s a good chance that the code will not do the right thing.Casting through a union (such as litb’s
my_reint) is probably the best solution, although it does technically violate the rule that if you write to a union through one member and read it through another, it results in undefined behavior. However, practically all compilers support this, and it results in the the expected result. If you absolutely desire to conform to the standard 100%, go with the bit-shifting method. Otherwise, I’d recommend going with casting through a union, which is likely to give you better performance.