C Mastery / Aliasing and Strict Aliasing
Part 2 — The Object Model and Undefined Behavior

Aliasing and Strict Aliasing

This chapter explains aliasing — two pointers referring to the same object — and the strict aliasing rule that restricts which types may alias. This is the rule that makes many pointer-cast tricks undefined behavior.

Why This Matters

Strict aliasing is not a compiler whim; it is what enables aggressive optimization. When you violate it, the compiler may produce code that does something completely different from what you expect, because it assumed your two pointers could not alias.

Prerequisites

Core Concept

Aliasing

Two lvalues alias when they designate the same object (or overlapping objects). For example:

int x = 5;
int *a = &x;
int *b = &x;   /* a and b alias */

The strict aliasing rule

An object may be accessed only through an lvalue of one of these types:

1. a type compatible with the object's effective type; 2. a qualified version of a compatible type; 3. the signed/unsigned type corresponding to the effective type; 4. an aggregate/union type that contains one of the above among its members (with restrictions); 5. a character type (char, signed char, unsigned char).

Accessing through any other type is undefined behavior. VERIFIED

The character-type exception is why you can always inspect raw bytes with unsigned char or memcpy.

Examples

int x = 5;
int *p = &x;
int y = *p;   /* ok: int lvalue */
unsigned int u = 5;
int *p = (int *)&u;
int v = *p;   /* ok: int and unsigned int correspond */

Illegal: unrelated types

float f = 1.0f;
int *p = (int *)&f;
int x = *p;   /* UNDEFINED BEHAVIOR: int is not an allowed alias for float */

The character-type exception

unsigned char *bytes = (unsigned char *)&f;
unsigned char first = bytes[0];   /* ok: inspecting representation */

How It Works

The compiler performs alias analysis to determine whether two memory accesses can refer to the same location. If they cannot (per the strict aliasing rule), it may reorder them, cache values in registers, or vectorize loops. When you violate the rule, the compiler's analysis is wrong, and the generated code may not do what the source "obviously" does.

Variations

restrict as a stronger promise

restrict (c.ptr.restrict) tells the compiler a pointer does not alias any other pointer used to access the object, enabling even more optimization than strict aliasing alone.

Unions and aliasing

Reading a union member other than the active one is generally not a well-defined way to alias types in C17; prefer memcpy (see c.union.punning).

Common Mistakes

same."

Undefined Behavior

allowed list). VERIFIED

object). VERIFIED

Portability

later standards). The exact list of allowed types is standard.

Under the Hood

Alias analysis feeds optimization passes such as instruction scheduling, dead-store elimination, and auto-vectorization. The -fstrict-aliasing flag (GCC/Clang) is on by default at -O2; -fno-strict-aliasing disables the assumption (used by some legacy codebases that violate the rule).

Practical Usage

alias.

Exercises

1. Write a program that reads an int as an unsigned int (legal) and as a float (illegal); run the illegal one under UBSan. 2. Demonstrate the character-type exception by inspecting a struct's bytes. 3. Reinterpret a float as uint32_t using memcpy and compare with a pointer cast. 4. Explain how restrict differs from the strict aliasing rule.

Deep Challenge

Explain, using strict aliasing and effective type, why this common "fast float-to-int bits" idiom is UB and provide a well-defined replacement:

float f = 1.0f;
uint32_t bits = *(uint32_t *)&f;   /* ? */

Then discuss how memcpy (or C23's bit_cast-style approach) solves it.

References

Verification

verified.`

Progress

Concept checkboxes

Mastery levels

ConceptCurrent level (0–8)Target level
c.obj.aliasing07