|
1 | 1 | /*
|
2 |
| -# NULL |
| 2 | +# null pointer constant |
3 | 3 |
|
4 |
| - Good source: <http://c-faq.com/null/macro.html> |
| 4 | + Good source: http://c-faq.com/null/macro.html |
5 | 5 |
|
6 | 6 | Basic usage: indicate error as return value from function
|
| 7 | +
|
| 8 | + C99 7.17/3 Common definitions `<stddef.h>` says: |
| 9 | +
|
| 10 | + # NULL |
| 11 | +
|
| 12 | + > NULL: macro which expands to an implementation-defined null pointer constant; |
| 13 | +
|
| 14 | + Then form the definition of "null pointer constant", it is either of: |
| 15 | +
|
| 16 | + - `0` |
| 17 | + - `(void*)0` |
| 18 | +
|
| 19 | + Thus in x86-64, is it possible to differentiate them by size: |
| 20 | + `0` is 4 bytes, while `(void*)` is 8. |
| 21 | +
|
| 22 | + C++: |
| 23 | +
|
| 24 | + - ensures that NULL is an "rvalue of integer type that evaluates to zero" (`0`): |
| 25 | + it cannot be a pointer. |
| 26 | +
|
| 27 | + - introduces the related `nullptr`, which is guaranteed to be a pointer type. |
| 28 | +
|
| 29 | + This is specially important because of function overload. |
| 30 | +
|
| 31 | + # Null pointer constant |
| 32 | +
|
| 33 | + # Null pointer |
| 34 | +
|
| 35 | + Null pointer constant and null pointer are note the same thing!!! |
| 36 | +
|
| 37 | + 6.3.2/3 Pointers: |
| 38 | +
|
| 39 | + > An integer constant expression with the value 0, or such an expression cast to type |
| 40 | + void *, is called a null pointer constant.55) If a null pointer constant is converted to a |
| 41 | + pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal |
| 42 | + to a pointer to any object or function. |
| 43 | +
|
| 44 | + 6.3.2/4 Pointers: |
| 45 | +
|
| 46 | + > Conversion of a null pointer to another pointer type yields a null pointer of that type. |
| 47 | + Any two null pointers shall compare equal. |
| 48 | +
|
| 49 | + Therefore there are multiple `null` pointer types: `(void *)0`, `(int *)0`, etc. |
| 50 | +
|
| 51 | + # argc[argv] |
| 52 | +
|
| 53 | + Null pointer |
| 54 | +
|
| 55 | + 5.1.2.2.1/2 Program startup: |
| 56 | +
|
| 57 | + > argv[argc] shall be a null pointer. |
7 | 58 | */
|
8 | 59 |
|
9 | 60 | #include "common.h"
|
10 | 61 |
|
| 62 | +int *ip; |
| 63 | + |
11 | 64 | int main() {
|
12 | 65 | /*
|
13 |
| - Why it works: it never points to any possible valid memory location. |
14 |
| - (`&` operator never gives anything equal to it). |
15 |
| - this is so guaranteed that gcc emmits a warning in the following code |
| 66 | + It never points to any possible valid memory location: |
| 67 | + global, local variable, malloc return, ... |
| 68 | +
|
| 69 | + In other words, taking `&` of a variable never gives it. |
16 | 70 | */
|
17 | 71 | {
|
18 | 72 | int i = 0;
|
19 | 73 | /* WARN GCC 4.7 warning: &i will never be null. Smart. */
|
20 | 74 | /*assert(&i != NULL);*/
|
21 | 75 | }
|
22 | 76 |
|
23 |
| - /* How it prints like: */ |
24 |
| - printf("NULL = %p\n", NULL); |
| 77 | + /* |
| 78 | + How it prints like: implementation defined. |
25 | 79 |
|
26 |
| - /* `if(NULL)` and `if(!NULL)` in error checking code always work as expected */ |
27 |
| - assert(!NULL); |
| 80 | + C99 7.19.6.1/8 The fprintf function: |
| 81 | +
|
| 82 | + > `p`: The argument shall be a pointer to void. The value of the pointer is |
| 83 | + converted to a sequence of printing characters, in an implementation-defined |
| 84 | + manner. |
| 85 | + */ |
| 86 | + { |
| 87 | + printf("printf NULL %%p = %p\n", NULL); |
| 88 | + } |
28 | 89 |
|
29 | 90 | /*
|
30 |
| - # NULL macro vs 0 |
| 91 | + # == for null pointers |
31 | 92 |
|
32 |
| - Relationship to 0: typecasting `(int)0` to any pointer type as |
33 |
| - `(int*)0`, `(char*)0` always gives NULL. |
| 93 | + Treated specially at 6.5.9/5 Equality operators: |
34 | 94 |
|
35 |
| - This is a valid way of representing the NULL pointer, |
36 |
| - but it is better style to always use the `NULL` macro |
| 95 | + > If one operand is a pointer and the other is a |
| 96 | + null pointer constant, the null pointer constant is converted to the type of the pointer. |
37 | 97 |
|
38 |
| - The exact definition of `NULL` is implementation dependant. |
39 |
| - A very common implementation is as `(void*)0`. |
| 98 | + And 6.5.9/6: |
40 | 99 |
|
41 |
| - C++11 also introduces the related `nullptr`. |
| 100 | + > Two pointers compare equal if and only if both are null pointers, [...] |
42 | 101 | */
|
43 | 102 | {
|
44 |
| - assert(NULL == (int*)0); |
45 |
| - assert(NULL == (char*)0); |
46 |
| - printf("sizeof(NULL) = %zu\n", sizeof(NULL)); |
| 103 | + /* |
| 104 | + True, since both are null pointers. |
| 105 | +
|
| 106 | + TODO error or warning? WARN GCC 4.8: comparison of distinct pointers without cast. |
| 107 | + */ |
| 108 | + { |
| 109 | + /*assert((char *)0 == (int *)0);*/ |
| 110 | + } |
| 111 | + |
| 112 | + /* |
| 113 | + True: one is a pointer, and the other is a null pointer constant. |
| 114 | + */ |
| 115 | + { |
| 116 | + assert((char *)0 == NULL); |
| 117 | + |
| 118 | + /* Above is converted to: */ |
| 119 | + assert((char *)0 == (char *)NULL); |
| 120 | + |
| 121 | + /* True because `0` is a null pointer constant: */ |
| 122 | + assert((char *)0 == 0); |
| 123 | + |
| 124 | + /* |
| 125 | + True because NULL is either: |
| 126 | +
|
| 127 | + - `0` |
| 128 | + - `(void *)0`, which is a null pointer constant |
| 129 | + */ |
| 130 | + assert(NULL == 0); |
| 131 | + } |
| 132 | + |
| 133 | + /* |
| 134 | + As a consequence, if(p) can be used directly on null checks, |
| 135 | + as it is equivalent to: |
| 136 | +
|
| 137 | + if (p != 0) |
| 138 | + */ |
| 139 | + { |
| 140 | + if (NULL) |
| 141 | + assert(false); |
| 142 | + } |
47 | 143 | }
|
48 | 144 |
|
49 |
| - /* ERROR: comparison of distinct pointer types requires a cast: */ |
| 145 | + /* WARN: comparison of distinct pointer types requires a cast: */ |
50 | 146 | {
|
51 | 147 | /*assert((int*)0 == (char*)0);*/
|
52 | 148 | }
|
53 | 149 |
|
54 | 150 | /*
|
55 | 151 | Never dereference the NULL pointer since it is guaranteed to point to nothing.
|
56 | 152 |
|
57 |
| - TODO to ANSI C, undefined behaviour? or guaranteed error? |
58 |
| -
|
59 |
| - May lead to a Segmentation fault. |
| 153 | + TODO Undefined behaviour? On Linux leads to a Segmentation fault. |
60 | 154 | */
|
61 | 155 | {
|
62 | 156 | /*volatile int i = *(int*)NULL;*/
|
|
0 commit comments