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_tis the same as for a pointer to character type. An object representation of the valuenullptris 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.
IMO it is UB:
6.3.2.3
If a null pointer constant or a value of the type nullptr_t (which is necessarily the value
nullptr)...
6.5.4.4
A pointer type shall not be converted to any floating type. A floating type shall not be converted to any pointer type. The type nullptr_t shall not be converted to any type other than void , bool or a pointer type. No type other than
nullptr_tshall be converted tonullptr_t
Here you convert void * to nullptr_t via union which is explicitly prohibited.
You can convert nullptr_t to void * via this union but not void * to nullptr_t
IMO nullptr_t exists only to introduce nullptr constant and I do not see any practical use of this type.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With