Consider this union:
typedef union
{
void* vptr;
nullptr_t nptr;
} pun_intended;
nullptr_t
is supposedly compatible with void*
1). Ok so what if we initialize the void*
to some non-zero value?
pun_intended foo = { .vptr = (void*)42 };
nullptr_t
was introduced.Full example:
#include <stdio.h>
#include <inttypes.h>
#include <stddef.h>
typedef union
{
void* vptr;
nullptr_t nptr;
} pun_intended;
int main(void)
{
pun_intended foo = { .vptr = (void*)42 };
printf("Value: %" PRIuPTR "\n", (uintptr_t)foo.vptr);
if(foo.nptr != (void*)42)
{
puts("It does not have value 42.");
if(foo.nptr == nullptr)
puts("Because it's a nullptr.");
else
puts("But it's not a nullptr.");
unsigned int val = *(unsigned char*)&foo; // little endian assumption here
printf("And it has value %d.\n", val);
if(foo.vptr != nullptr)
{
puts("foo.vptr is however not a nullptr.");
}
}
}
Output on clang 16 -std=c2x:
Value: 42
It does not have value 42
Because it's a nullptr
And it has value 42.
foo.vptr is however not a nullptr
Output on gcc 13.2 -std=c2x:
Value: 42
It does not have value 42.
But it's not a nullptr.
And it has value 42.
foo.vptr is however not a nullptr.
My question: Is anything of the above (which was previously well-defined or impl.defined) now undefined/unspecied behavior? If so, where is that stated? Or are these scenarios simply not considered in C23 - a defect?
1) Source: C23 n3096 draft 7.21.2
The size and alignment of
nullptr_t
is the same as for a pointer to character type. An object representation of the valuenullptr
is the same as the object representation of a null pointer value of typevoid*
.
Ok so what if we initialize the
void*
to some non-zero value?
C 2023 N3096 7.21.2 3 explicitly answers this. After telling us that the representation of a nullptr
value in the nullptr_t
type is the same as for a null pointer value in the void *
type, it tells us what happens if there is a different sequence of byte values in a nullptr_t
object:
… if the object representation is different, the behavior is undefined.