The following snippet is, of course, not a good idea
Yeah but only because it doesn't compile on a conforming C compiler. char *vram = 0xB8000;
is not even valid C, and like all invalid C is has undefined behavior. See "Pointer from integer/integer from pointer without a cast" issues.
This code however is fine:
char *vram = (char*)0xB8000;
memset(vram, 32, 0x18000);
What happens there is beyond the scope of the C language.
volatile char *LCDC = 0xFF40;
char LCDCshadow = *LCDC;
Same bug with no cast leading to invalid C here. Otherwise perfectly fine code.
And if it's the latter, how does one generate a valid pointer with a value of 0?
The integer constant 0
, or that constant cast to a void pointer (void*)0
is a special item called null pointer constant. Whenever a pointer is assigned a null pointer constant, that pointer will get transformed into a null pointer. The actual contents of a null pointer is implementation-defined. Upon encountering code like int* ptr = 0;
, the compiler may give ptr
any value that makes sense for the given implementation - not necessarily 0
.
For example:
uint8_t data [sizeof(int*)];
int* ptr = 0;
memcpy(data, &ptr, sizeof(int*));
This doesn't necessarily result in data
being 00 00 00 00
for a 32 bit pointer - it is implementation-defined.
This was how the language was designed, with some confused intention to handle exotic addresses etc. In practice though, this means that we can never create a pointer to the physical address zero. So systems that have such a physical address - most notably pretty much every single microcontroller system created - don't treat null pointers any differently, as C intended. Because they need to use the physical address 0. Meaning that accessing a null pointer on such a system will result in an access to address 0.
I've had bugs in real-world systems where an accidental null pointer access caused I/O ports to go active and hardware misbehaving because of it.
So it boils down to the fact that null pointers is a known language design mistake. They should have used a keyword null
that couldn't be mixed up with address 0
. C++ has attempted to fix this in later standards, but C remains broken.