It seems reasonable to amend the C standard to say "That's not an assertion of being non-null" (and more generally to make &invalid_pointer->item and &invalid_pointer[n] valid; IIRC implementing offsetof as (size_t)(((type *)NULL)->member) is UB). Would that prevent any significant optimizations?
Also does the rule that pointers can only point to elements of allocated objects or one-past-the-end enable any significant optimizations?
> Also does the rule that pointers can only point to elements of allocated objects or one-past-the-end enable any significant optimizations?
Yes, for segmented architectures like the 8086, it means that pointers don't have to be normalized after every operation. That is, when you increment or decrement a pointer, you only need to do the operation on the offset, you don't have to touch the segment. When all you have is less than 10 MHz, every operation counts.
(For those who don't remember the 8086, it's not as simple as concatenating the segment and the offset to obtain the physical address: to get the 20-bit physical address from the 16-bit segment and the 16-bit offset, the formula is segment*16+offset. As a consequence, the same memory location could be accessed through several distinct segment:offset pairs. If the memory allocator chose the segment value right, objects of 64 KiB or less could be indexed by doing all operations on the offset value, without having to touch the segment value.)
It seems reasonable to amend the C standard to say "That's not an assertion of being non-null" (and more generally to make &invalid_pointer->item and &invalid_pointer[n] valid; IIRC implementing offsetof as (size_t)(((type *)NULL)->member) is UB). Would that prevent any significant optimizations?
Also does the rule that pointers can only point to elements of allocated objects or one-past-the-end enable any significant optimizations?