Is this always the case? If so, why isn't this part of the standard?
Most of the time, but not necessarily. There's various oddball architectures with segmented memory areas. The C standard also wants to allow pointers to be some abstract items, that are not necessarily equivalent to physical addresses.
Also, in theory if you have something like this
int a;
int b;
int* pa = &a;
int* pb = &b;
if (pa < pb) // undefined behavior
puts("less");
else
puts("more");
Then the compiler could in theory replace the whole if-else with puts("more")
, even if the address of pa
is lower than the address of pb
. Because it is free to deduct that pa
and pb
cannot be compared, or that comparing them always gives false. This is the danger of undefined behavior - what code the compiler generates is anyone's guess.
In practice, the undefined behavior in the above snippet seems to lead to less efficient code, on -O3 with gcc and clang x86. It compiles into two loads of the addresses and then a run-time comparison. Even though the compiler should be able to calculate all addresses at compile time.
When changing the code to well-defined behavior:
int a[2];
int* pa = &a[0];
int* pb = &a[1];
Then I get much better machine code - the comparison is now calculated at compile time and the whole program is replaced by a simple call to puts("less")
.
On embedded systems compilers however, you are almost certainly able to access any address as if it was an integer - as a well-defined non-standard extension. Otherwise it would be impossible to code things like flash drivers, bootloaders, CRC memory checks etc.