81

Is it safe to assume that NULL always translates to false in C?

void *somePtr = NULL;

if (!somePtr) {
  /* This will always be executed? */
}

Or should an explicit check against the value of NULL be made?

An̲̳̳drew
  • 13,375
  • 13
  • 47
  • 46
Sydius
  • 13,567
  • 17
  • 59
  • 76

13 Answers13

83

Yes. NULL evaluates to false, since C considers any non-zero value true and any zero value false. NULL is essentially the zero address and is treated as such in comparisons, and I believe would be promoted to an int for the boolean check. I would expect that your code is readable to anyone familiar with C although I would probably make the check explicit.

In C and C++ programming, two null pointers are guaranteed to compare equal; ANSI C guarantees that any null pointer will be equal to 0 in a comparison with an integer type; furthermore the macro NULL is defined as a null pointer constant, that is value 0 (either as an integer type or converted to a pointer to void), so a null pointer will compare equal to NULL.

Ref: http://en.wikipedia.org/wiki/Null_pointer#Null_pointer

Eric Pigeon
  • 1,091
  • 2
  • 10
  • 21
tvanfosson
  • 524,688
  • 99
  • 697
  • 795
  • 4
    An explicit check may be clearer in some cases, but this is a C idiom that is guaranteed by the language to be valid. :) – Greg D Jan 20 '09 at 01:01
  • 2
    i would have cried if all my c code using those if stuffs is now invalid :) – Johannes Schaub - litb Jan 20 '09 at 01:06
  • The standard isn't very clear on the issue: it's guaranteed that 0 cast to a pointer type will be a null pointer, but afaik it does not specify what will happen when a null pointer is cast to int! – Christoph Jan 20 '09 at 01:10
  • 3
    you don't cast to int though. you compare 0 to the pointer. 0 is a null pointer constant. and if you compare a null pointer constant to a pointer, the null pointer constant will become a null pointer of the right type. and a null pointer compares unequal to every valid pointer. that's what he wants – Johannes Schaub - litb Jan 20 '09 at 01:14
  • The situation in the standard is more convoluted: it allows null pointer to have address eg. 0xdeadbeef, but IMHO still evaluate to false. That's because there is no conversion in the if-clause, the condition should have scalar type (pointer is a scalar type) and NULL pointer compares equal to 0 – jpalecek Jan 20 '09 at 01:16
  • 1
    yes jpalecek that's the whole point. a "null pointer" does not mean "zero bits". a null pointer is a black-box. In the if, the " != 0" is implicit, and in !ptr, the "== 0" is implicit. so if you do if(ptr), it will compare the pointer to a null pointer constant. – Johannes Schaub - litb Jan 20 '09 at 01:21
  • Perhaps tvanfosson could scratch the part about the promotion to an integer for the boolean check? – Christoph Jan 20 '09 at 01:28
  • 1
    `NULL is essentially the zero address` this is not quite correct. NULL is 0 when converted to a numeric value, but the value of the null pointer may be non-zero [Is NULL always zero in C?](https://stackoverflow.com/q/9894013/995714). The address 0 may be valid, esp. on embedded systems – phuclv Nov 30 '19 at 06:02
  • Referencing a Wikipedia isn't a good idea... Any ref to the standards? – Yasushi Shoji Feb 26 '21 at 06:46
22

The 'C' language dates from an era where (void*)0 could actually be a valid pointer. It is not that long ago, the 8080 and Z80 microprocessors had an interrupt vector at address 0. Faced with such architecture choices, it couldn't do anything but let a header file declare the value of NULL. There were some compilers out there, now long forgotten, where NULL was not equal to (void*)0 (0xffff was the next alternative), thus giving your if() statement undefined behavior.

C++ mercifully put an end to this, a null pointer is assignable from and testable against 0.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • MMUs were probably more significant than C++ in the change. – Jonathan Leffler Jan 20 '09 at 01:00
  • 2
    About your C++ sentence: that's wrong. 0 is not a null pointer. 0 is a null pointer constant. void *p = 0; now, p is a null pointer. it's a difference, because a null pointer has pointer type, where a null pointer constant has integer type and is a constant expression – Johannes Schaub - litb Jan 20 '09 at 01:03
  • 3
    C99 guarantees that 0 cast to a pointer type will be a null pointer as well - I never bothered to read previous standards, so no idea when this happened... – Christoph Jan 20 '09 at 01:03
  • *"giving your if() statement undefined behavior."* — [C FAQ disagrees](http://c-faq.com/null/ptrtest.html) – jfs Jun 16 '16 at 15:50
  • Not that long ago, the 8086 through the 80686 had an interrupt vector at address 0 in real mode. – S.S. Anne Nov 25 '19 at 12:20
  • 2
    0 still remains a perfectly valid address on every arch I have written mmu-code for. It is just a convention of many C runtimes that invalidate its use. In modern linux, as root, you can mmap an object to 0 with MAP_FIXED. In not-long-ago UNIX, it was common to map a read-only zero page to zero so that strcmp(NULL, ...) would not cause a fault, but would only match an empty string. – mevets Nov 25 '19 at 20:23
19

It's never safe to assume anything.

An explicit check is also more clear about what you're testing.

akatakritos
  • 9,836
  • 1
  • 23
  • 29
  • 1
    We used to take it one step further and define a type-specific nil value for each of our typedef'ed items: structs, int, longs, whatever. That way the conditional would read "if (foo != fooNil) { etc. }". Disclaimer: I used to work for Simonyi at Xerox so my brain was contaminated. – Peter Rowell Jan 20 '09 at 00:52
  • 2
    @Peter Rowell: for quite a long time, I used #define NIL(x) ((x)0) to achieve roughly that effect: NIL(foo), NIL(char *), NIL(bar), etc. – Jonathan Leffler Jan 20 '09 at 01:02
  • 1
    @Jonathan: in which language - C or C++? In C99, that's unnecessary, because 'Any two null pointers shall compare equal.' – Christoph Jan 20 '09 at 01:05
17

Yes (at least for any standards compliant C compiler!)

From the comp.lang.c FAQ:

Q: Is the abbreviated pointer comparison ``if(p)'' to test for non-null pointers valid? What if the internal representation for null pointers is nonzero?

A: It is always valid.

Community
  • 1
  • 1
Captain Segfault
  • 1,686
  • 8
  • 11
13

My copy of ISO/IEC 9899:TC3 (Committee Draft — Septermber 7, 2007) says:

6.3 Conversions

1 Several operators convert operand values from one type to another automatically.

6.3.2.3 Pointers

3 An integer constant expression with the value 0 [...] is called a null pointer constant. If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function.

So far, ptr!=0 is true (1) for every non-null ptr, but it's still open, how two null pointers compare.

6.5.9 Equality operators

5 [...] If one operand is a pointer and the other is a null pointer constant, the null pointer constant is converted to the type of the pointer.

6 Two pointers compare equal if and only if both are null pointers, both are [...]

Hence, ptr==0 is 1 (and ptr!=0 is 0), if and only if ptr is a null pointer.

6.5.3.3 Unary arithmetic operators

5 The result of the logical negation operator ! is 0 if the value of its operand compares unequal to 0, 1 if the value of its operand compares equal to 0. The result has type int. The expression !E is equivalent to (0==E).

So the same holds for !ptr.

6.8.4.1 The if statement

1 The controlling expression of an if statement shall have scalar type.

2 In both forms, the first substatement is executed if the expression compares unequal to 0.

Note, that a scalar type is an arithmetic type or a pointer type (see "6.2.5 Types", clause 21). Putting it together, we have:

  • if (ptr) succeeds ⇔ ptr!=0 is 1 ⇔ ptr is not a null pointer.
  • if (!ptr) succeeds ⇔ ptr==0 is 1 ⇔ ptr is a null pointer.
Community
  • 1
  • 1
Ralph
  • 335
  • 2
  • 5
  • 2
    The cited document is available on http://www.open-std.org/jtc1/sc22/wg14/www/standards – Ralph Nov 28 '19 at 19:47
7

Yes, if(!p) is valid and guaranteed to work.

An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant. If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function.

https://port70.net/~nsz/c/c11/n1570.html#6.3.2.3p3

This means that (void*)0 is a null pointer. It also means that if p is a pointer, then p==0 is equivalent to p==(void*)0.

It also means that if p is a not a null pointer, then p==(void*)0 will evaluate to 0.

So far, so good.

Conversion of a null pointer to another pointer type yields a null pointer of that type. Any two null pointers shall compare equal.

http://port70.net/~nsz/c/c11/n1570.html#6.3.2.3p4

Note that "Any two null pointers shall compare equal." This means that if p is a null pointer, then p==0 will evaluate to true, because 0 will be promoted to (void*)0 which is a null pointer. It also mean that no non-null pointer can be equal to a null pointer.

Let's have a look at the negation operator.

The result of the logical negation operator ! is 0 if the value of its operand compares unequal to 0, 1 if the value of its operand compares equal to 0. The result has type int. The expression !E is equivalent to (0==E).

http://port70.net/~nsz/c/c11/n1570.html#6.5.3.3p5

This tells us that !p is the same as p==0 by definition, which is the same as p==(void*)0 as mentioned above.

And taking the fact that all null pointers are equal into consideration, this means that p==(void*)0 can only evaluate to true if p is a null pointer and and only false if p is not a null pointer.

So yes, if(!p) is a perfectly safe way to check if p is a null pointer or not.

klutt
  • 30,332
  • 17
  • 55
  • 95
4

NULL is just a preprocessor definition. It's in stdio.h. Typically, only an insane person would redefine it, but it's possible. An example:

#include <stdio.h>
#ifdef NULL
#undef NULL
#endif
#define NULL 1

void main()
{

        if (NULL)
                printf("NULL is true\n");
        else
                printf("NULL is false\n");
}

This code will print "NULL is true". Try it if you don't believe me. Your compiler might not even warn you that you're doing something weird.

bdowling
  • 425
  • 2
  • 4
  • 2
    But if you define NULL to 1 and assign somePtr = NULL, you'll at least get a warning that you're converting an integer to a pointer. – Mark James Jan 20 '09 at 06:11
  • Interesting. You can make it not warn by doing: #define NULL (void *) 1 – bdowling Jan 21 '09 at 00:10
  • 4
    That would be plain wrong. The compiler and the C standard library are bundled together for a reason. If you mess with it, you are breaking this. – Spidey Nov 30 '12 at 12:11
3


What is NULL?

The macro NULL is defined in <stddef.h> (and other headers) as a null pointer constant;


What is the value of the null pointer constant?

An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant.

Example Definition:

#define NULL ((void*)0)


Evaluating if(NULL)

if ( expression ) statement

if ( expression ) statement else statement

In both forms, the first substatement is executed if the expression compares unequal to 0. In the else form, the second substatement is executed if the expression compares equal §6.8.4.1 Language 133 ISO/IEC 9899:TC3 Committee Draft — Septermber 7, 2007 WG14/N1256 to 0. If the first substatement is reached via a label, the second substatement is not executed.


So yes if the compiler is compliant with ISO C99 you can assume that the statement below will always execute.

if (!NULL) { statement; } 


Above quotations are from ISO/IEC 9899:1999 (C99). You can read it here.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
Mike Seeds
  • 400
  • 3
  • 10
3

Yes it:

C standard 6.3.2.3

An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant.If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function.

and 6.3.2.6

Any pointer type may be converted to an integer type. Except as previously specified, the result is implementation-defined. If the result cannot be represented in the integer type, the behavior is undefined. The result need not be in the range of values of any integer type.

-

When any scalar value is converted to _Bool, the result is 0 if the value compares equal to 0; otherwise, the result is 1

0___________
  • 60,014
  • 4
  • 34
  • 74
0

NULL is defined as a constant pointer that is guaranteed to point to a useless/non-existent place in memory. Most implementations of NULL are ((void *)0) but it is not mandatory that this is so.

dreamlax
  • 93,976
  • 29
  • 161
  • 209
  • In C, that's correct. Be aware that in C++, it is most frequently just 0, mainly because you can't convert a void pointer to any other type without an explicit cast. – Jonathan Leffler Jan 20 '09 at 00:58
  • 5
    In any correct C compiler "NULL == 0" is true, even if a null pointer does not really contain 0. What you can't do is memzero a pointer and then assume it will be NULL. – Captain Segfault Jan 20 '09 at 01:14
0

According to me, it's not always safe to assume that. Since, depending on which headers have been included in a program, it can have been redefined. But according to the standard, the null pointer constant is guaranteed not to point to any real object and has a type void *.

In our case, the declaration void *somePtr = NULL could also be void *somePtr = 0 with 0 as null pointer.

“An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant. If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function.” https://www.geeksforgeeks.org/few-bytes-on-null-pointer-in-c/

That simply means, evaluating *somePtr at that specific point could result to false.

Another reference can be https://www.gnu.org/software/libc/manual/pdf/libc.pdf at page 944 A.3 about NULL Pointer Constant

Gratien Asimbahwe
  • 1,606
  • 4
  • 19
  • 30
-2

Yes, mostly.

First off, NULL is a typedef. I could royally screw you over by saying in a previously included header

#define NULL 1

This might not make a lot of sense, but since when has other people's code ever made sense? :)

Also, while it's probably syntactically safe, it's not semantically correct. NULL means "nothing", neither true or false or a boolean value or int or string. It means "a symbol for nothing". So testing for NULL is more like a philisophical issue: If a tree falls in the forest, and if(listener), does it make a sound?

Do everyone a favor and be clear about testing against NULL.

Matt
  • 10,434
  • 1
  • 36
  • 45
-6

*NULL always targets to 0x00L. You can consider that false, but to be sure always do an explicit check.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Gabriel Sosa
  • 7,897
  • 4
  • 38
  • 48
  • 2
    NULL is implementation specific. In some cases, such as embedded machines, you may want to access the very first byte in RAM which would be addressed as 0. NULL is defined by the standard as a pointer that is guaranteed not to point to any usable point in RAM. – dreamlax Jan 20 '09 at 00:38
  • Dereferencing either NULL itself or a null pointer invokes undefined behaviour -- or, on big enough machines with MMUs, a core dump or equivalent. The "all the world's a VAX" syndrome died a while ago - there, derefencing NULL did yield a zero byte. – Jonathan Leffler Jan 20 '09 at 01:03
  • The lower 128 bytes of a vax machine give an access violation when you dereference them. Do you have a program that demonstrates the symptoms you observed? – EvilTeach Jan 20 '09 at 01:44