Code takes the address of a float, reinterprets it as a pointer to unsigned int, edits the exponent bits and reads the float back. It works at -O0 and returns stale values at -O2. Name the rule broken, say what the compiler did, and give the two correct ways to write it.
Code takes the address of a float, reinterprets it as a pointer to unsigned int, edits the exponent bits and reads the float back. It works at -O0 and returns stale values at -O2. Name the rule broken, say what the compiler did, and give the two correct ways to write it.
Approach: Look at which types the standard permits to access one object, then ask what a compiler may assume about two pointers whose types are unrelated.
The code breaks the strict aliasing rule, so the compiler assumed the float pointer and the unsigned int pointer cannot name the same object, kept the float in a register across the integer store and reloaded a stale value, and the correct forms are std::memcpy between the two objects or std::bit_cast. An object may be accessed only through a pointer to its own type, a cv qualified version of that type, the signed or unsigned counterpart of the same integer type, or a character type, and float and unsigned int are none of those for each other. Both memcpy and bit_cast compile to zero extra instructions at -O2 for a 4 byte object, so the correct version costs nothing. Union based type punning is defined in C and undefined in C++, and -fno-strict-aliasing hides the problem by disabling that optimisation across the whole translation unit.
Follow-up: What does the same rule say about reading a market data header through a pointer to a packed struct laid over a receive buffer?
Key concepts: strict aliasing, type punning, memcpy, bit_cast.