4 ms·
This is one of the most unfortunate cases of UB in C. It's necessary because C largely doesn't forbid pointer aliasing (accessing an object using multiple, dist
by NobodyNada 2y ago
This is one of the most unfortunate cases of UB in C. It's necessary because C largely doesn't forbid pointer aliasing (accessing an object using multiple, distinct pointers). But the compiler needs to have some idea of when pointers might alias; otherwise, it's forced to generate extremely inefficient code that redundantly loads pointers over and over again just in case the value changed unexpectedly.
Within the body of a single function, the compiler can see where addresses came from and figure out what pointers may or may not alias. But when pointers are passed in as function parameters, the compiler has no idea. Thus, the C standard allows compilers to assume that pointers to different types never refer to the same object; an assumption that's true for almost all code anyone would want to write. But this adds surprising undefined behavior to some things you might try, like casting between layout-compatible structs, or the fast inverse square root trick from Quake. (Casting a pointer to a different type can still be tricky to get right even if it wasn't UB though. Alignment requirements are another footgun: for example, it's not legal to cast a uint8_t pointer to a uint16_t pointer unless you're sure its address is even.)
The blessed-by-the-standard way to do type punning is to either use a union or a memcpy, not a pointer cast.
For comparison, Rust prohibits mutable pointer aliasing for safe reference types, so the compiler knows when references may or may not alias. (Raw pointers are assumed to always be aliasable unless the compiler can prove that they're unique, e.g. by being derived from a safe reference). This leads to more efficient codegen in many cases, but it also means that type punning through pointer casting is fully legal in unsafe code (provided validity and alignment requirements are met), since the compiler does not need the type information to figure out aliasing.
- kevin_thibedeau 2y ago> But when pointers are passed in as function parameters, the compiler has no idea. "restrict" was added to give the compiler an idea.