Ch5.13: Strict Aliasing Rule

Overview

The strict aliasing rule is one of the most subtle and dangerous parts of C++. It allows compilers to assume that pointers of different, unrelated types never refer to the same memory.

In practice, the strict aliasing rule is often ignored by programmers, misunderstood, or violated accidentally.

Violating the rule results in undefined behavior that can silently produce incorrect results even when the code “looks correct”.

In this chapter, you will learn:

1. What is aliasing?

Two pointers alias when they refer to the same object.


int x{42};

int *p = ::std::addressof(x);
int *q = ::std::addressof(x);   // p and q alias the same int

If one modifies the object, the other sees the change. Aliasing becomes dangerous when the pointers have different types.

2. What the strict aliasing rule says

The compiler may assume that pointers to unrelated types do not alias the same object.

“Unrelated types” means types that are not:

If you access an object through a pointer of an unrelated type, the compiler is allowed to assume that this access never happens → undefined behavior.

3. Why the strict aliasing rule is often ignored

Many programmers come from languages where type punning is harmless, or they learned C from old books that used reinterpret_cast-style tricks.

As a result, real-world codebases often contain:

These patterns may “seem to work” on some compilers or architectures, but they are still undefined behavior and can break under optimization.

The fact that strict aliasing violations often appear to work does not make them safe.

4. Allowed aliasing

Same type (ignoring const)


int x{42};

int *p = ::std::addressof(x);
int const *q = ::std::addressof(x);   // ok

char / unsigned char / std::byte views


int x{0x12345678};

unsigned char *bytes =
    reinterpret_cast(::std::addressof(x));

Reading these bytes is always allowed.

5. Forbidden aliasing (undefined behavior)

Accessing an object through a pointer of an unrelated type


float f{1.0f};

int *p = reinterpret_cast<int*>(::std::addressof(f));

// *p = 0;   // ❌ undefined behavior

Type punning through reinterpret_casted pointers


int x{42};

float *pf = reinterpret_cast<float*>(::std::addressof(x));

// float y = *pf;   // ❌ undefined behavior

6. Why strict aliasing exists

Strict aliasing enables aggressive compiler optimizations.

If the compiler can assume that pointers of unrelated types do not alias, it can:

Violating the rule breaks these assumptions and leads to unpredictable behavior.

7. Safe ways to inspect raw memory

These patterns are always safe:

8. Safe type punning with ::std::bit_cast

In Ch2.13: Casting, we introduced ::std::bit_cast as the modern, safe way to reinterpret the raw bits of an object. This is the correct replacement for dangerous pointer-based type punning.

If you need to reinterpret the bits of a value as another type, use ::std::bit_cast. Do not use pointer casts.


#include <bit>

float f{1.0f};

// Safe: reinterpret the bits of float as std::uint32_t
std::uint32_t u = ::std::bit_cast<std::uint32_t>(f);

Incorrect (undefined behavior)


float f{1.0f};
std::uint32_t *p = reinterpret_cast<std::uint32_t*>(::std::addressof(f));

// std::uint32_t u = *p;   // ❌ undefined behavior

Correct


float f{1.0f};
std::uint32_t u = ::std::bit_cast<std::uint32_t>(f);   // ✔ safe

9. As a last resort: [[__gnu__::__may_alias__]] (GCC extension)

If you truly must alias through pointers, GCC provides a non‑standard escape hatch: [[__gnu__::__may_alias__]].

This is not standard C++. It is non-portable and should only be used by experts who fully understand strict aliasing.


// Detect whether [[__gnu__::__may_alias__]] is supported (GCC and Clang)
#if __has_cpp_attribute(__gnu__::__may_alias__)
#  define MAY_ALIAS [[__gnu__::__may_alias__]]
#else
#  define MAY_ALIAS
#endif

// Create an alias type for "int*" that is allowed to alias anything
using may_alias_int_ptr = int * MAY_ALIAS;

float f{1.0f};

// Allowed by GCC and Clang (non-portable)
may_alias_int_ptr p = reinterpret_cast(::std::addressof(f));

// GCC/Clang will not assume this violates strict aliasing
int bits = *p;

This attribute disables strict aliasing for that type only.

Prefer ::std::bit_cast whenever possible.

10. Recommended talk: Type punning in modern C++

For a deep, modern explanation of strict aliasing and type punning, watch this CppCon 2019 talk by Timur Doumler:

“Type punning in modern C++ – Timur Doumler – CppCon 2019”

You do not need to understand every detail yet. For now, focus on the core message: type punning through pointers is dangerous, and strict aliasing is the reason why.

Key takeaways