cpp core · advanced
Strict Aliasing & Type Punning
Strict aliasing lets the compiler assume that pointers to unrelated types never refer to the same object, which enables it to keep values in registers and reorder loads and stores. Reading a float's storage through a uint32_t* therefore breaks the rule and is undefined behavior: it may appear to work in a debug build yet read a stale value, garbage, or be optimized away at -O2. The correct way to reinterpret an object's bytes is to copy them into a brand-new object of the target type — with std::memcpy (which compilers fold to a single move) or, in C++20, std::bit_cast, which is constexpr and self-documenting. Union type punning is defined in C but technically UB in C++, so prefer bit_cast/memcpy for portability. The exception to strict aliasing is char/unsigned char/std::byte pointers, which may alias any object.
Reading an object through a pointer of an incompatible type violates strict aliasing and is undefined behavior — the optimizer assumes differently-typed pointers never alias — so pun bits safely by copying into a new object with std::memcpy or std::bit_cast (C++20), never via reinterpret_cast.
The code
float f = 1.0f; // storage bytes: 3F 80 00 00
// (1) UB: type punning through a pointeruint32_t bad = *reinterpret_cast<uint32_t*>(&f); // strict-aliasing violation
// (2) OK: copy the bytes into a real uint32_tuint32_t ok1;std::memcpy(&ok1, &f, sizeof f);
// (3) OK, C++20: same bytes, brand-new object, constexprauto ok2 = std::bit_cast<uint32_t>(f);
// union punning: fine in C, technically UB in C++union { float f; uint32_t u;} pun; // read pun.u after writing pun.fWhat this lesson walks through
- 01The goal — and the tempting trap
- 02Strict aliasing: distinct types can't alias
- 03Why it actually bites at -O2
- 04Fix #1: std::memcpy into a real object
- 05Fix #2: std::bit_cast (C++20)
- 06Union punning: a C habit, not C++
- 07Pun bits by copying, never by casting
We want the raw bit pattern of f (1.0f -> 0x3F800000). The tempting move is to cast the float's address to a uint32_t* and dereference it. It even prints the right number... which is exactly why the bug survives.
See it animated — step by step, at your own pace
Unlock the full interactive walkthrough of Strict Aliasing & Type Punning and 100+ animated C++ interview lessons.