A pointer points to the start of its pointee - i.e. the point "just before" its pointee. That's how derived-to-base casts work. That's also how you can have "one-past-the-end" pointers, which are actually "just after" the relevant array.
for example, if you have the following structs
typedef struct { void *key; } base;
typedef struct { base b; int misc; int data[2]; } derived;
Yep. A pointer is a memory range, but it supports a cast operation that allows you to change the pointer type, and therefore the end address. I think we agree, right? :)
Hmm, yeah, void pointers are weird. I'd be inclined to say that its start and end address are the same and it's a range over 0 bytes of memory, and the fact that dereferencing fails is an artifact of the dereferencing operation itself... but I don't know enough about void pointer voodoo to know whether that's actually a consistent interpretation.
Comments
A pointer points to the start of its pointee - i.e. the point "just before" its pointee. That's how derived-to-base casts work. That's also how you can have "one-past-the-end" pointers, which are actually "just after" the relevant array.
for example, if you have the following structs
then derived is laid out as followsYep. A pointer is a memory range, but it supports a cast operation that allows you to change the pointer type, and therefore the end address. I think we agree, right? :)
Except you can have a void* that does not have an end address.
Hmm, yeah, void pointers are weird. I'd be inclined to say that its start and end address are the same and it's a range over 0 bytes of memory, and the fact that dereferencing fails is an artifact of the dereferencing operation itself... but I don't know enough about void pointer voodoo to know whether that's actually a consistent interpretation.