Literally, does (char *) 0 mean a pointer to some location that contains a zero? Does the system create such an address with value 0 for each such declaration?
No, it's a cast of 0 to type char *. That is, a null pointer. A 0 in any pointer context refers to the null pointer constant.
What exactly it points to doesn't matter - dereferencing it would cause undefined behaviour.
For more, check out the C FAQ Part 5: Null Pointers.
It is null pointer value of type char *.
From the C++ Standard
A null pointer constant can be converted to a pointer type; the result
is the null pointer value of that type
And from the C Standard
3 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.
4 Conversion of a null pointer to another pointer type yields a null
pointer of that type. Any two null pointers shall compare equal.
It is not a pointer that points to a locarion that contains 0. So the system creates nothing. As it is written in the C Standard the null pointer "is guaranteed to compare unequal to a pointer to any object or function". So it is used to determine whether a pointer points to some object or function.
its an explicit cast to a null pointer. i believe there is a #define macro for it allowing you to just write NULL
Related
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...
The book Understanding and Using C Pointers, by Richard Reese says:
The null concept is an abstraction supported by the null pointer
constant. This constant may or may not be a constant zero. A C
programmer need not be concerned with their actual internal
representation.
My question is, since "this constant may or may not be a constant zero," is it safe for me to do things like the below in my code:
int *ptr = NULL;
// Some code which probably sets ptr to a valid memory address
if(!ptr)
{
ERROR();
}
If NULL is not 0, there is a chance that the if clause will evaluate to true.
Is it safe to assume that the NULL constant is zero?
NULL will compare equal to 0.
NULL is very commonly a zero bit pattern. It is possible for NULL to be a non-zero bit pattern - but not seen these days.
OP is mixing as least 4 things: NULL, null pointer constant, null pointer, comparing a null pointer to 0. C does not define a NULL constant.
NULL
NULL is a macro "which expands to an implementation-defined null
pointer constant" C17dr § 7.19 3
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. C17dr § §
6.3.2.3 3
Thus the type of a null pointer constant may be int, unsigned, long, ... or void * .
When an integer constant expression1, the null pointer constant value is 0. As a pointer like ((void *)0), its value/encoding is not specified. It ubiquitously does have the bit pattern of zeros, but is not specified so.
There may be many null pointer constants. They all compare equal to each other.
Note: the size of a null pointer constant, when it is an integer, may differ from the size of an object pointer. This size difference is often avoided by appending a L or two suffix as needed.
null pointer
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. C17dr § § 6.3.2.3 3
Conversion of a null pointer to another pointer type yields a null
pointer of that type. Any two null pointers shall compare equal. C17dr
§ § 6.3.2.3 4
The type of null pointer is some pointer, either an object pointer like int *, char * or function pointer like int (*)(int, int) or void *.
The value of a null pointer is not specified. It ubiquitously does have the bit pattern of zeros, but is not specified so.
All null pointer compare as equal, regardless of their encoding.
comparing a null pointer to 0
if(!ptr) is the same as if(!(ptr != 0)). When the pointer ptr, which is a null pointer, is compared to 0, the zero is converted to a pointer, a null pointer of the same type: int *. These 2 null pointers, which could have different bit patterns, compare as equal.
So when it is not safe to assume that the NULL constant is zero?
NULL may be a ((void*)0) and its bit pattern may differ from zeros. It does compare equal to 0 as above regardless of its encoding. Recall pointer compares have been discussed, not integer compares. Converting NULL to an integer may not result in an integer value of 0 even if ((void*)0) was all zero bits.
printf("%ju\n", (uintmax_t)(uintptr_t)NULL); // Possible not 0
Notice this is converting a pointer to an integer, not the case of if(!ptr) where a 0 was converted to a pointer.
The C spec embraces many old ways of doing things and is open to novel new ones. I have never came across an implementation where NULL was not an all zeros bit pattern. Given much code exist that assumes NULL is all zero bits, I suspect only old obscure implementations ever used a non-zero bit-pattern NULL and that NULL can be all but certain to be an all zero bit pattern.
1 The null pointer constant is 1) an integer or 2) a void*. "When an integer ..." refers to the first case, not a cast or conversion of the second case as in (int)((void*)0).
if(!ptr) is a safe way to check for a NULL pointer.
The expression !x is exactly equivalent to 0 == x. The constant 0 is a NULL pointer constant, and any pointer may be compared for equality against a NULL pointer constant.
This holds true even if the representation of a null pointer is not "all bits 0".
Section 6.5.3.3p5 of the C standard regarding the ! operator states:
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).
And section 6.3.2.3p3 regarding pointer conversions 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.
chux has written a good, detailed answer, but regarding that book specifically, I'd be sceptic about its quality:
This constant may or may not be a constant zero
This is wrong, it must always be a zero or a zero cast to a void*. The definition of a null pointer constant is found in C17 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.
This means that all integer constant expressions like 0, 0L, 0u, 0x0, '\0' etc are null pointer constant. If any of them is cast to a void*, it is also a null pointer constant.
A C programmer need not be concerned with their actual internal representation.
The author is obviously mixing up the two formal terms null pointer constant and null pointer. A programmer do not need to concern themselves with the internal representation of a null pointer. They do need to know what makes a valid null pointer constant though. The safest, most readable way being to use the NULL macro, which is guaranteed to be a null pointer constant.
So regarding your question "is it safe for me to do things like the below in my code" - yes it is perfectly safe to do !ptr to check for a null pointer, even though ptr==NULL is more readable code.
Consider I have a structure
typedef struct point_t
{
int x;
int y;
}POINT;
I create a pointer to pointer for POINT and initialize it to NULL.
POINT **ppPoint = NULL;
Should *ppPoint also return NULL ?
The fact that there are 2 layers of pointers here is actually irrelevant. The fact that your outer pointer in NULL means it is illegal to dereference it. Therefore it is not meaningful to ask what value you would get by dereferencing it.
Consider this:
int *p = NULL; // modern practice would be to use nullptr anyway
if (0 == *p) // this is Undefined Behaviour!
{
// do something, maybe?
}
You are just adding another layer to this, where instead of int, you have point_t*, but it really makes no difference.
The thing with Undefined Behaviour is that anything can happen! Your program might crash, or it might appear to work, or it might give you garbage values sometimes, or it might ...
A null pointer does not point to anything. That applies to ordinary pointers, function pointers and member pointers alike. It also applies to pointers to pointers.
Therefore, it doesn't make sense to talk about the value of "what it points to".
You can't dereference a pointer which has a value of NULL. So you won't be able to access *ppPoint.
You can check the address of a variable with the %p formater in a printf() to check.
printf("Address of ppPoint: %p", *ppPoint);
printf("Address of *ppPoint: %p", *ppPoint);
First, there's the usual misconceptions about the mysterious null. In this case there's 3 related terms:
null pointer
null pointer constant
The NULL macro
A null pointer constant is the integer 0 or that integer cast to a pointer, (void*)0. The NULL macro is guaranteed to be a portable null pointer constant.
Whenever you assign a null pointer constant, such as NULL, to any pointer, that pointer becomes a null pointer. This allows compilers to internally represent a null pointer as something else than 0, because the address 0x00...00 is quite often a valid physical address on many systems.
Specifically, C17 6.3.2.3/3 defines this:
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.
When accessing a null pointer by de-referencing it, with don't get any predictable result. This is undefined behavior as per C17 6.5.3.2/4:
If an invalid value has been assigned to the pointer, the behavior of the unary * operator is undefined.
Meaning anything can happen. If you are lucky, you just get a system crash.
You can however compare a null pointer against another null pointer, or against a null pointer constant, and they are guaranteed to be equal (C17 6.5.9).
As for pointer-to-pointer being some a special case, it is not. The pointed-at type is irrelevant for any of the above mentioned rules. Overall there is nothing special with pointer-to-pointer in C - it is never a special case, but always to be regarded as pointer-to-type.
I want initialize a function pointer so that it is null. Which of these two ways is preferred?
void (*Pointer)(void) = NULL;
Or
void (*Pointer)(void) = (void (*)(void))0;
0 is implicit convertible to any pointer type. Though how your compiler implements NULL depends.
In your code you can simply write
void (*Pointer)(void) = 0; but it won't be portable , so write void (*Pointer)(void) = NULL;
The standard (ISO/IEC 9899:2011) says:
§6.3.2.3 Pointers
¶1 A pointer to void may be converted to or from a pointer to any object type. A pointer to any object type may be converted to a pointer to void and back again; the result shall compare equal to the original pointer.
¶2 For any qualifier q, a pointer to a non-q-qualified type may be converted to a pointer to the q-qualified version of the type; the values stored in the original and converted pointers shall compare equal.
¶3 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.
¶4 Conversion of a null pointer to another pointer type yields a null pointer of that type. Any two null pointers shall compare equal.
…
¶8 A pointer to a function of one type may be converted to a pointer to a function of another type and back again; the result shall compare equal to the original pointer. If a converted pointer is used to call a function whose type is not compatible with the referenced type, the behavior is undefined.
66) The macro NULL is defined in <stddef.h> (and other headers) as a null pointer constant; see 7.19.
§7.19 Common definitions <stddef.h>
¶3 The macros are
NULL
which expands to an implementation-defined null pointer constant; …
All of which adds up to say that either of the notations used in the question is valid and they (and other similar expressions) are equivalent and there will be no problem.
void (*Pointer)(void) = NULL;
void (*Pointer)(void) = (void (*)(void))0;
void (*Pointer)(void) = 0;
Do note that the standard doesn't explicitly say you can convert a pointer to an object type into a pointer to a function type, or vice versa, or that round-tripping is guaranteed to work. Remember, there were once memory models for early Intel machines where data (object) pointers were a different size from function pointers — and that can still happen on other machines (IBM AS/400 and its heirs and successors is another example).
You could also study the questions and answers on the null pointer from http://c-faq.com/.
NULL is defined to be a null pointer constant. A null pointer constant can be used to initialise any pointer (data pointer or function pointer) to a null pointer of the correct type, so assigning NULL is just fine.
0 will also work, because 0 is also a null pointer constant. So will 0L, (13*12-156) and many other ways. NULL is preferred because it shows your intent to assign a null pointer.
The line below that is just unnecessary work.
In C, what is the difference between a NULL pointer and a pointer that points to 0?
The ISO/IEC 9899:TC2 states in 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
The macro NULL expands to an implementation-defined null pointer constant.
Any two null pointers shall compare equal.
Yes there is. The standard dictates that NULL always points to invalid memory. But it does not state that the integer representation of the pointer must be 0. I've never come across an implementation for which NULL was other than 0, but that is not mandated by the standard.
Note that assigning the literal 0 to a pointer does not mean that the pointer assumes the integer representation of 0. It means that the special null pointer value is assigned to the pointer variable.
Evaluating the literal 0 in a pointer context is identical to NULL. Whatever bit pattern the compiler uses to represent a NULL pointer is hidden.
The old comp.lang.c FAQ has a big section on the null pointer and it's worth a read.
comp.lang.c null pointers
The idea is that a NULL pointer should somehow represent a memory area that is invalid.
So since in the lower memory segments the OS code is mapped, the value of 0 has been used (to represent the NULL pointer) since this area in memory does not belong to the user's program but is mapped to the OS code.