C allows NULL
to be defined to any null pointer constant, in other words, any integer constant expression that evaluates to 0, or such an expression cast to void *
. My question concerns whether the choice of definition really matters, i.e. whether an otherwise-correct program might depend on which definition is used. For the purpose of this question, I'd like to ignore issues like NULL
being passed to variadic functions or functions lacking prototypes, since I've already dealt with it separately. Let's assume sizeof NULL == sizeof(void *)
and sizeof NULL == sizeof(T)
for some integer type T
, so that sizeof
is not sufficient to answer the question of whether NULL
has pointer type.
Obviously, C11 provides a way to distinguish the type of NULL
or any other expression: the _Generic
keyword.
C99 also provides one obscure way that seems to be reliable:
int null_has_ptr_type()
{
char s[1][1+(int)NULL];
int i = 0;
return sizeof s[i++], i;
}
Are there any other methods by which the type of NULL
may be determined by a conforming C program? Any that work in C89?
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.
b) To pass a null pointer to a function argument when we don't want to pass any valid memory address. c) To check for null pointer before accessing any pointer variable. So that, we can perform error handling in pointer related code e.g. dereference pointer variable only if it's not NULL.
If any pointer is being compared to 0, then this is a check to see if the pointer is a null pointer. This 0 is then referred to as a null pointer constant. The C standard defines that 0 is typecast to (void *) is both a null pointer and a null pointer constant. The macro NULL is provided in the header file “stddef.h”.
At the very high level, we can think of NULL as a null pointer which is used in C for various purposes. Some of the most common use cases for NULL are a) To initialize a pointer variable when that pointer variable isn’t assigned any valid memory address yet. b) To check for a null pointer before accessing any pointer variable.
Evaluating the expression (int*)0yields a null pointer of type int*. (int*)0is not a null pointer constant. A null pointer constantis a particular kind of expression that may appear in C source code. A null pointeris a value that may occur in a running program.
NullPointerException is a RuntimeException. In Java, a special null value can be assigned to an object reference. NullPointerException is thrown when program attempts to use an object reference that has the null value.
Through the question, answers, and comments, I think we established:
_Generic
).typedef
.So the answer seems to be that there's no reliable pre-C11 method, and seemingly no valid pre-C99 method.
Get the string definition of NULL and then do an as complete check as you want. Here is a very simple minded one:
#define XSTR(x) #x
#define STR(x) XSTR(x)
if (STR(NULL)[0] == '(') {
...
}
But I don't know how you'll handle a __null
which can come out from that.
Couldn't you stringify the macro and look at the string?
# include <stddef.h>
# include <stdio.h>
# include <string.h>
# define STRINGIFY(x) STRINGIFY_AUX(x)
# define STRINGIFY_AUX(x) #x
int main(void)
{
const char *NULL_MACRO = STRINGIFY(NULL);
if (strstr("void", NULL_MACRO) != NULL)
puts("pointer");
else
puts("integer");
}
It correctly prints "integer"
if you add this (usually NULL
has pinter type):
# undef NULL
# define NULL 0
NULL
cannot be something like (int) ((void *) 0)
because the standards doesn't state that a null pointer constant converted to an integer type is still a null pointer constant.
Furthermore, the standard also say this about integer constant expressions (C11, 6.6/6):
An integer constant expression117) shall have integer type and shall only have operands that are integer constants, enumeration constants, character constants,
sizeof
expressions whose results are integer constants,_Alignof
expressions, and floating constants that are the immediate operands of casts. Cast operators in an integer constant expression shall only convert arithmetic types to integer types, except as part of an operand to thesizeof
or_Alignof
operator.
EDIT: actually this doesn't work with things like:
# define NULL (sizeof(void *) - sizeof(void *))
(thanks for noticing) and this cannot be checked in a trivial way as the OP needs, a little bit of work (simple parsing) is required.
EDIT 2: and there are also typedef
as comment correctly pointed out.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With