When C++17 changed the abstract pointer model, it changed all non-null type-punned pointers from "points to no object (but still denotes an address)" to "points to an object (just not the one the pointer type suggests)". In doing so, it accidentally made pointer arithmetic
([expr.add])
on type-punned pointers well-defined (but unimplementable when sizeof(T) != sizeof(element) for a T*).
For example:
#include <iostream>
short* cast(long* p) { return reinterpret_cast<short*>(p); }
int main() {
long a[2];
// gcc says 0. Standard says 1.
std::cout << (cast(a) + 1 == (void*)(a + 1)) << "\n";
// gcc says 4 on x86-64. Standard says 1.
std::cout << (cast(a + 1) - cast(a)) << "\n";
}