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