Question based on discussion of the answer about sizeof NULL .

Here are the standard pieces:

If you want to see a void *

NULL which expands to a null pointer constant

It seems that instead of #define NULL ((void*)0) , it is not forbidden to simply #define NULL 0 , as is done in pluses. Then it turns out that sizeof NULL is equal to either sizeof (void*) or sizeof (int) (in the variant sizeof 0 ).

However, @Vlad from Moscow claims that NULL in C must be a pointer.

NULL in C is defined as a pointer.

The words "cast to type void *" are of key importance in the above quotation.

Here, или is related not to the casting, but to the form of the expression. And this is exactly how NULL is defined.

So is it permissible for C (without pluses) to have?

 #define NULL 0 

And if it is acceptable, then why is it used in compilers?

 #ifndef NULL #ifdef __cplusplus #define NULL 0 #else #define NULL ((void *)0) #endif #endif 

instead of a simpler version with zero for both languages?
After all, in C, even the overloading of functions was not possible, so that something could be broken.

  • May help get answers. In this question, SO has a link to the resource comp.lang.c Frequently Asked Questions and in particular to the list of null pointer questions -> the answer to 5.16 . Apparently, in C, NULL is always a pointer. - Alex Krass
  • I don’t know exactly how this is done, but, for example, gcc understands that the list of execl arguments must end with a null (constant (!)) Pointer (it doesn’t matter (void *)0 or at least (float *)0 ). By the way, he understands, even if unistd.h is not included. Therefore, to use everywhere just 0 will not work. - avp
  • one
    @KoVadim only __nonnull((1, 2)) refers to the first and second call list arguments, not the last (its compiler calls sentinel and the warning: missing sentinel in function call [-Wformat=] ) warning: missing sentinel in function call [-Wformat=] . Moreover, it is somewhere written for execl (and obviously, heaps of other functions), because when I remove unistd.h and manually prescribe the same execl and execf declarations, I only swear on execl - avp
  • one
    Ha, in theory (void *)0 != 0 . I think it's easy to understand why. - 0andriy

1 answer 1

After reviewing the standard C carefully, I think you are right. null pointer constant is either an integer constant expression with a value of 0, or such an expression cast to void * .

Therefore, the definition of a macro NULL may be different in principle, depending on the implementation of the compiler. That is, nowhere in the C standard, I did not find that the NULL macro should be defined as

 ( void *)0 

I looked into the document Rationale for International Standard — Programming Languages ​​— C and found the following there (7.17 Common definitions)

25 NULL pointer constant. Thus, you can choose to define it as (void *) 0. This is where the sizeof (void *) is.

Since the null pointer constant is converted in expressions to a null pointer , and the size of the null pointer may not be equal to any integer type, it is more convenient to define the null pointer constant as

 ( void * )0 

that is, immediately bring it to the type of pointer.

In C ++, such a definition was refused, since, unlike C in C ++, in connection with type safety, you need to explicitly cast a pointer to void to a pointer type to a specific object. That is, if the null pointer constant NULL is defined in C ++ as

 ( void *)0 

then you have to do an explicit pointer mapping, like for example

 int *p = ( int * )( void *)0; 

which is naturally very burdensome.

Therefore, in C ++, they refused to declare NULL as an integer constant, converted to the void * type.

  • 0L - an unexpected option ... Although logical, perhaps. And there is no requirement to match the size with the pointer size? That is, is it just a note that does not commit to anything? - Qwertiy
  • one
    In modern pluses, NULL is not recommended at all. There is a nullptr . - αλεχολυτ