Explains pointer provenance in C — the compiler's abstract notion of which object a pointer legitimately belongs to, distinct from its raw numeric address. Covers why aliasing rules exist, how casting through uintptr_t or memcpy typically preserves provenance, why pointer subtraction across unrelated objects is undefined behavior, how strict aliasing relates to provenance, and how these rules let compilers eliminate redundant memory loads for faster code. Ends by teasing a follow-up on std::launder.

11m read timeFrom towardsdev.com
Post cover image
Table of contents
Provenance Rules You Need to Know

Questions this post answers

Why does dereferencing a pointer that mathematically equals another variable's address still count as undefined behavior in C?

Because pointers carry provenance, an abstract identity tied to the object they were derived from, not just a numeric address. Even if pointer p is mathematically stepped to have the exact same integer value as &y, the compiler's abstract machine still treats p as belonging to x. Dereferencing p to access y is undefined behavior because equal addresses do not grant provenance to access a different object. Developers debugging aliasing-related undefined behavior can dig deeper into C semantics via daily.dev.

Does casting a pointer to uintptr_t and back preserve its provenance in C?

In practice, most compilers treat a simple round-trip from pointer to uintptr_t, through bitwise math, and back to a pointer as preserving provenance, as long as the resulting pointer still targets the same object. However, the C standard's guarantees for this pattern are limited and still being clarified by working groups like WG14, so pointer-tagging tricks relying on this behavior carry some risk. Anyone relying on low-level pointer tricks can track evolving C standard guidance through daily.dev.

Why does subtracting two unrelated int pointers cause undefined behavior in C even before considering provenance?

Subtracting two pointers is only well-defined when both point into the same array object; if they point to different objects entirely, like two separate int variables x and y, the subtraction itself is undefined behavior regardless of provenance. When the pointers do share an array object, the resulting difference is a plain integer offset that carries no provenance of its own. Systems programmers hardening pointer arithmetic against UB can find deep-dive explanations via daily.dev.

69 Impressions