Consider a C99 program that reads from a read-only binary blob linked into the program's binary through a linkerfile. The program knows where the blob starts in memory, but its layout is not known during compilation. The blob consists of unsigned 32-bit, and 64-bit integers. We took care to make sure that their endianness corresponds to (data) endianness on the used platform. We also took care to put the blob in memory such that it is 4B aligned.
Requirements:
(performance) We want to read both 32-bit and 64-bit integers with minimum number of instructions, based on the possibilities of individual platforms (e.g. to use single load instruction where applicable)
- we do not want to read the value byte-by-byte and then use shifting and adding to reconstruct the 4B/8B integer.
(portability) This program must run on ARM, x86_64 and MIPS architectures. Also some architectures have 32-bit system bus, others have 64-bit bus.
- we do not want to have to maintain arch-specific adaptations for each architecture with inlined assembly code.
- we do not want to make assumptions about used toolchain, e.g. we don't want to use
-fno-strict-aliasing
and similar.
Seemingly, this could be done with type-punning. We know where in the memory is the value we want to read and we can cast the pointer from original (unsigned char*
) to one of uint32_t*
, uint64_t*
.
But C99's strict aliasing rules confuse me.
There will be no aliasing, of that we can be sure - we would not be punning on the same memory location to two different types that are not unsigned char
. The layout of the binary blob does not allow this.
Question:
Is casting a const uint8_t*
to const uint32_t*
, or const uint64_t*
well-defined in C99, as long as we are sure we do not alias the same pointers to both const uint32_t*
and const uint64_t*
?