Search code examples
cnullnull-pointernullptrc23

C23 and memory representation of nullptr


I'm reading the C document n3042 Introduce the nullptr constant

and when it enumerates the properties of nullptr there is the following:

  • In memory, nullptr is represented with the same bit-pattern as a null pointer constant of type void*

so if I write the following code is it reliable to verify what the previous property asserts?

void* null_ptr1 = NULL;    
void* null_ptr2 = nullptr;   

if (memcmp(&null_ptr1, &null_ptr2, sizeof(void*)) == 0) 
    printf("binary rep. of NULL and nullptr is the same.\n");
else 
    printf("binary rep. of NULL and nullptr is not the same.\n");

Solution

  • so if I write the following code is it reliable to verify what the previous property asserts?

    The C language spec does not forbid there being multiple distinct null pointer representations for any given pointer type. If there is more than one, then it does not specify which NULL and nullptr correspond to, or even that either one of them always corresponds to the same one. Therefore, as far as the spec is concerned, your program might print "binary rep. of NULL and nullptr is not the same."

    Additionally, as @PaulHankin described in comments, your program is not even testing what you seem to intend for it to test. If you want to examine the (a) representation of nullptr then you need to look at an object of type nullptr_t. Converting nullptr to type void * by assignment produces a null pointer of type void *, but there is no guarantee that this preserves representation if there is more than one option for representation. Your test would be more appropriately written as:

    static_assert(sizeof(void *) == sizeof(nullptr_t));
    void* null_ptr1 = NULL;    
    nullptr_t null_ptr2 = nullptr;
    
    if (memcmp(&null_ptr1, &null_ptr2, sizeof(void*)) == 0) 
        printf("binary rep. of NULL and nullptr is the same.\n");
    else 
        printf("binary rep. of NULL and nullptr is not the same.\n");
    

    I think it's pretty unlikely that you would observe a difference in practice, even on an implementation that did have multiple null pointer representations for type void *, but the spec does not guarantee that you won't.