Why is there a NULL in the C language? - c

Why is there a NULL in the C language? Is there a context in which just plain literal 0 would not work exactly the same?

Actually, you can use a literal 0 anyplace you would use NULL.
Section 6.3.2.3p3 of the C standard states:
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 section 7.19p3 states:
The macros are:
NULL
which expands to an implementation-defined null pointer constant
So 0 qualifies as a null pointer constant, as does (void *)0 and NULL. The use of NULL is preferred however as it makes it more evident to the reader that a null pointer is being used and not the integer value 0.

NULL is used to make it clear it is a pointer type.
Ideally, the C implementation would define NULL as ((void *) 0) or something equivalent, and programmers would always use NULL when they want a null pointer constant.
If this is done, then, when a programmer has, for example, an int *x and accidentally writes *x = NULL;, then the compiler can recognize that a mistake has been made, because the left side of = has type int, and the right side has type void *, and this is not a proper combination for assignment.
In contrast, if the programmer accidentally writes *x = 0; instead of x = 0;, then the compiler cannot recognize this mistake, because the left side has type int, and the right side has type int, and that is a valid combination.
Thus, when NULL is defined well and is used, mistakes are detected earlier.
In particular answer to your question “Is there a context in which just plain literal 0 would not work exactly the same?”:
In correct code, NULL and 0 may be used interchangeably as null pointer constants.
0 will function as an integer (non-pointer) constant, but NULL might not, depending on how the C implementation defines it.
For the purpose of detecting errors, NULL and 0 do not work exactly the same; using NULL with a good definition serves to help detect some mistakes that using 0 does not.
The C standard allows 0 to be used for null pointer constants for historic reasons. However, this is not beneficial except for allowing previously written code to compile in compilers using current C standards. New code should avoid using 0 as a null pointer constant.

It is for humans not compilers.
if I see in the code p = NULL; instead of p = 0; it is much easier for me to understand that p is a pointer not the integer.
For compilers it does not matter, for humans does.
Same as we use definitions instead of "raw" values or expressions or human readable variable names like loopCounter instead of p755_x.

Why is there a NULL in the C language?
To help make clear the assignment implies a pointer and not an integer.
Example: strtok(char *s1, const char *s2); in both cases below receive a null pointer as the NULL and 0 are both converted to a char *. The first is usually considered better self-documentation. As a style issue, follow your group's coding standard.
strtok(s, NULL);
strtok(s, 0;
Is there a context in which just plain literal 0 would not work exactly the same?
Yes - when the original type is important.
0 is an int
NULL is a void *, or int, unsigned or long or long long, etc. It is implementation defined.
Consider a function that takes a variable number of pointers, with a sentinel null pointer to indicate the last.
foo("Hello", "World", NULL); // might work if `NULL` is a pointer.
foo("Hello", "World", 0);
As the arguments as 0 and NULL are not converted when passed to a ... function (aside from some promotions), the function foo() might not access them the same. Portable code would use:
foo("Hello", "World", (char*) NULL);
// or
foo("Hello", "World", (char*) 0);
A difference may also occur when NULL, 0 are passed to _Generic

The integer constant literal 0 has different meanings depending upon the context in which it's used. In all cases, it is still an integer constant with the value 0, it is just described in different ways.
Namely, the most common purposes of NULL pointer are:
To initialize a pointer variable when that pointer variable isn’t
assigned any valid memory address yet.
To check for a null pointer before accessing any pointer
variable. By doing so, we can perform error handling in pointer
related code e.g. dereference pointer variable only if it’s not
NULL.
To pass a null pointer to a function argument when we don’t want
to pass any valid memory address.(ref)

Related

Is both NULL and false are equivalent to 0 (the int value)? [duplicate]

So, I had an argument with my professor earlier defending that NULL is not a pointer, but he kept on insisting that it is because there is such a thing as NULL pointer. So, here I am now a little bit confused if NULL is really a pointer or not
I already tried search over the internet but couldn't find any answer, so my last resort is here
In C, NULL is a macro that expands to a null pointer constant.
7.19p3
The macros are
NULL which expands to an implementation-defined null pointer constant;
...
A null pointer constant is an integer constant expression with the value 0 (
e.g., 0, 1-1, 42*0LL, etc.) or such an expression cast to (void*).
6.3.2.3p3
An integer constant expression with the value 0, or such an expression
cast to type void *, is called a null pointer constant.66) 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.
Most common C implementations define NULL to be 0, 0L, or ((void*)0).
So you are correct. NULL need not be a pointer.
(IIRC, C++ doesn't even allow the (void*) cast in NULL, meaning NULL in C++ always has integer type. Because of that and because void* pointers
do not compare with regular pointers so readily in C++, C++>=11 now has a special nullptr keyword.)
NULL itself is not a pointer, it is a macro that can be used to initialize a pointer to the null pointer value of its type. When compared to a pointer, it compares equal if the pointer is a null pointer and unequal if the pointer is a valid pointer to an object of its type.
There is no semantic difference between char *p = 0; and char *p = NULL; but the latter is more explicit and using NULL instead of 0 is more informative in circumstances where the other operand is not obviously a pointer or if comparing to an integer looks like a type mismatch:
FILE *fp = fopen("myfile", "r");
if (fp == NULL) {
/* report the error */
}
Similarly, there is no semantical difference in C between '\0' and 0, they both are int constants. The first is the null byte, the second the null value. Using 0, '\0' and NULL wisely may seem futile but makes code more readable by other programmers and oneself too.
The confusion may come from misspelling or mishearing the null pointer as the NULL pointer. The C Standard was carefully proof read to only use null pointer and refer to NULL only as the macro NULL.
Note however that one the accepted definitions of NULL, #define NULL ((void*)0) makes NULL a null pointer to void.
There's nothing about the idea of a 'pointer to address 0' that's a problem.
The rule is that you're disallowed from derefencing it... it's allowed to exist, and if created will meet any criteria for "pointerhood" I can think of.
Just because it's not meaningfully a pointer to something...

Is NULL in C required/defined to be zero?

NULL appears to be zero in my GCC test programs, but wikipedia says that NULL is only required to point to unaddressable memory.
Do any compilers make NULL non-zero? I'm curious whether if (ptr == NULL) is better practice than if (!ptr).
NULL is guaranteed to be zero, perhaps casted to (void *)1.
C99, §6.3.2.3, ¶3
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.
And note 55 says:
55) The macro NULL is defined in <stddef.h> (and other headers) as a null pointer constant.
Notice that, because of how the rules for null pointers are formulated, the value you use to assign/compare null pointers is guaranteed to be zero, but the bit pattern actually stored inside the pointer can be any other thing (but AFAIK only few very esoteric platforms exploited this fact, and this should not be a problem anyway since to "see" the underlying bit pattern you should go into UB-land anyway).
So, as far as the standard is concerned, the two forms are equivalent (!ptr is equivalent to ptr==0 due to §6.5.3.3 ¶5, and ptr==0 is equivalent to ptr==NULL); if(!ptr) is also quite idiomatic.
That being said, I usually write explicitly if(ptr==NULL) instead of if(!ptr) to make it extra clear that I'm checking a pointer for nullity instead of some boolean value.
Notice that in C++ the void * cast cannot be present due to the stricter implicit casting rules that would make the usage of such NULL cumbersome (you would have to explicitly convert it to the compared pointer's type every time).
From the language standard:
6.3.2.3 Pointers
...
3 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.
...
55) The macro NULL is defined in <stddef.h> (and other headers) as a null pointer constant; see 7.17.
Given that language, the macro NULL should evaluate to a zero-valued expression (either an undecorated literal 0, an expression like (void *) 0, or another macro or expression that ultimately evaluates to 0). The expressions ptr == NULL and !ptr should be equivalent. The second form tends to be more idiomatic C code.
Note that the null pointer value doesn't have to be 0. The underlying implementation may use any value it wants to represent a null pointer. As far as your source code is concerned, however, a zero-valued pointer expression represents a null pointer.
In practice is the same, but NULL is different to zero. Since zero means there's a value and NULL means there isn't any. So, theoretically they are different, NULL having a different meaning and in some cases that difference should be of some use.
in practice no, !ptr is correct

Issue with NULL pointers on Harvard Architecture platform

Interesting issue we came across here this week.
We are working in C on a Harvard Architecture embedded platform, which has 16-bit data addresses and 32-bit code addresses.
The issue occurs when you are working with function pointers. If you have code like
if (fp) fp();
or
if (fp != 0) fp();
everything is fine.
However if you have code like
if (fp != NULL) fp();
then, because NULL is defined as (void *) 0, the compiler (gcc in this case) a) does not warn and b) does a 16-bit comparison against your function pointer instead of a 32-bit comparison. Fine as long as your function pointer doesn't happen to lie on a 64k boundary so all bottom 16 bits are 0.
At the moment we have large swathes of code which contain explicit checks against NULL. Most of them will be data pointers, but some of them will be function pointers. A quick grep for != NULL or == NULL revealed over 3000 results, to many to go through manually to check.
So, what we would like now would be either
a way to find all the cases where function pointers (but not data pointers) are compared (so we can instead have them compare against FP_NULL which we would define as a 32-bit 0), or
to redefine NULL in such a way that it would do the right thing.
(Or, I suppose, to
update our gcc port to detect and
correctly handle this case).
I can't think of any approach that works for 1. The only approach I can think of for 2 is to redefine NULL as a 0 function pointer, which would be very wasteful for the vast majority of comparisons which are against data pointers. (A 32-bit compare is 4 instructions, a 16-bit compare is 1 instruction).
Any thoughts or suggestions?
It seems to me the easiest way is replace all occurrences of NULL by 0. This works for function pointer (as you say) and object pointers.
This is a variant of (2) Redefine NULL to plain 0.
But the fact that you cannot compare function pointers with NULL is a bug in your implementation. C99 states that comparison of the null pointer constant is possible with both object and function pointers, and that NULL should expand to this constant.
Small addition from the C-FAQ question 5.8:
Q: Is NULL valid for pointers to functions?
A: Yes (but see question 4.13)
Mixing function pointers with (void *) 0
(A reply to R..'s comment). I believe using function pointers and (void *) 0 together is well-defined. In my reasoning I will refer to sections of the C99 draft 1256, but will not quote large parts to keep it readable. It should also be applicable to C89.
6.3.2.3 (3) defines the integer constant expression 0 and such an expressions cast to (void *) as null pointer constant. And: "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.8.9 defines the == and != operands for (among other) a pointer operand and a null pointer constant. For these: "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."
Conclusion: In fp == (void *) 0, the null pointer constant is converted to the type of fp. This null pointer can be compared to fp and is guaranteed to be unequal to fp if it points to a function. Assignment (=) has a similar clause, so fp = (void *) 0; is also well-defined C.
The way you describe should work:
6.3.2.3/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.
So, either NULL has been redefined to something not 0 or (void*)0 (or equivalent?) or your compiler is non-conformant.
Try redefining NULL yourself (to plain 0) after all the #includes in all files :-)
just for kicks: try gcc -E (to output the preprocessed source) on a problem file and check the expansion of NULL
You could try this:
#ifdef NULL
#undef NULL
#endif
#define NULL 0
Here are a few suggestions:
temporarily change NULL to (char*)0 or something else that is not implicitly convertible to a function pointer. This should give a warning about every comparison with a non-matching pointer. You could then run the produced compiler output through a tool like grep and look for a typical pattern for function pointers, like (*)(.
redefine NULL as 0 (without the cast to void*). This is another valid definition for NULL and might do the right thing for you, but no guarantees.
You could try a segment hack (really only a hack), so you can use the fast 16bit comparision, without any risk.
Create segements at each n*0x10000 boundary with size of 4 (or even smaller), so there never can't exists a real function.
It depends on your embedded device memory space, if this is a good or a really bad solution.
It could work if you have 1MB normal Flash, which will never change.
It will be painfull if you have 64MB Nand Flash.
Edit the implemention's system headers to replace all occurrances of
#define NULL ((void *)0)
with
#define NULL 0
Then file a bug report with the vendor. You should not have to modify your (perfectly correct, albeit ugly style) code because of a bug in the vendor's compiler.

How to set a pointer to zero'th location?

As per my knowledge, all occurrences of NULL in code are replaced by a 0 during the preprocessing stage. Then during compilation, all occurrences of 0 in pointer context are replaced by an appropriate value which represents NULL on that machine. Thus the compiler has to know that NULL value for that particular machine.
Now, this means that whenever I use 0 in pointer context, it is replaced by the appropriate value representing NULL on that machine, which may or may not be 0. So, how can I tell the compiler that I actually mean 0 and not NULL, when I use 0 in pointer context?
Sorry for the long description. Correct me if I am wrong
One way is to store all-bits-zero into your pointer:
void* zero;
memset(&zero, 0, sizeof(zero));
Well, there's no portable way to achieve that in C. C language provides no portable features specifically intended for aiming a pointer to a specific numerical address. However, the "secret" intent of the explicit integer-to-pointer conversion is actually just that: to implement the "natural" mapping between the integers and pointers, where "natural" normally means that the numerical value of the integer is preserved intact (if possible) when converting it to pointer type. In other words, all you need is an integer with 0 value. You just need to make sure that this integer does not qualify as an Integral Constant Expression, since otherwise it will be recognized as null-pointer constant. (In simple terms, you need a run-time integral zero, not a compile-time integral zero).
For example, this
uintptr_t i = 0;
void *p = (void *) i;
will normally produce a pointer pointing to address 0. Moreover, in C language (as opposed to C++) this
const uintptr_t i = 0;
void *p = (void *) i;
will also normally produce a pointer pointing to address 0. While this
void *p = 0; /* compile-time 0 will not do */
will produce the implementation-specific null-pointer value.
You can also take a look at C FAQ here, which covers this very issue.

C memset warning

This is my warning.
warning: passing argument 2 of ‘memset’ makes integer from pointer without a cast
Then i changed as follows (make NULL to 0)
Before Change : memset(key, NULL, KEY_BYTES);
After Change : memset(key, 0, KEY_BYTES);
The warning is removed.
i am using linux & gcc compiler,C.
Is it correct action
Depending on implementation, the C standard library sometimes defines NULL as a zero integer (which would avoid the warning you saw) but sometimes defines NULL as zero cast into a void pointer. The latter implementation causes the warning you saw.
To answer your specific question, you should not be using NULL in this case. Regardless of the implementation, NULL is intended to be used as a null pointer, not a synonym for integer zero. If you want to use memset to fill a block of memory with zeroes, then pass zero as the second argument, not NULL.
Quoting from http://en.wikipedia.org/wiki/Stdlib.h:
NULL
The stdlib.h and stddef.h header files define
the macro NULL, which yields a null pointer
constant, and represents a pointer value that
is guaranteed not to point to a valid
address in memory.
Variants
NULL may be defined as a
constant expression equal to int zero,
long int zero, or zero cast to a void
* pointer:
#define NULL 0
#define NULL 0L
#define NULL ((void *) 0)
Although the null pointer constant is always
represented in C by the symbolic
constant 0 or by 0 cast to a void
pointer, the actual bit representation
of such a pointer is system-specific
and may contain one-bits.
Possibly NULL is defined as ((void*)0). Both versions work correctly, but the second looks better - memset requires a number and not a pointer.
The second parameter to memset is of type int. NULL is the null pointer constant in C. According to the standard:
An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant.
So, NULL may be defined as (void *)0 or equivalent. In such a case, your memset call is wrong because you are converting a pointer to an integer.
The other way is okay: if you use 0 where a null pointer is expected, the compiler will do the conversion for you. So, given a type T, the following sets both p and q to the null pointer:
T *p = NULL;
T *q = 0;
Further, given a pointer p, the following are equivalent:
if (p) ...
if (p != NULL) ...
if (p != 0) ...
This is because 0 is special: in pointer contexts, it is automatically converted to the null pointer constant. A pointer on the other hand, is never converted to an integer implicitly. Any integer other than 0 is also never converted to a pointer implicitly.
Finally, in the code below, even though i has the value 0, it is not a null pointer constant in the assignment to p:
int i = 0;
int *p = i;
The above will trigger a warning when compiled in conformant mode.
(The above is a bit of a digression, but I hope it is not completely off-topic.)
Yes, they have the same effect. The compiler must be treating NULL as a special NULL pointer (whereas some more primitive compilers simply #define NULL 0), and the second parameter of memset is of type int, so by changing it to 0 you are using the null value but satisfying the int requirement.
memset accepts second argument as a character not any pointer.In your first call,you pass the NULL which is a pointer points to nothing in C.That's why,it gave error.In the second call,you 're assigning 0 bytes to the memory given.
When using memset(key, NULL, KEY_BYTES);
NULL is the (void*)0 {ie; void* typecasted of int zero}.
and the memset 2nd argument should be of type "unsigned int"
That is why it is showing warning.
Depending upon the compiler you are using it will behave.
Using gcc will make to warned (regarding data typecast) and will just accept nearest possible available value out of the given argument value.

Resources