Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why NULL is not predefined by the compiler

Tags:

c

This issue bothered me for a while. I never saw a different definition of NULL, it's always

#define NULL  ((void *) 0)

is there any architecture where NULL is defined diferently, and if so, why the compiler don't declare this for us ?

like image 819
stdcall Avatar asked Apr 20 '13 19:04

stdcall


People also ask

Is null predefined in C?

NULL is defined in stddef. h , you don't have to define it yourself at all. Even if an architecture has a null pointer that isn't all bits zero, replacing NULL with 0 must provide a null pointer through some compiler magic. 0 and NULL are interchangeable in C.

Why is null undefined in C?

This happens because NULL is not a built-in constant in the C or C++ languages. In fact, in C++, it's more or less obsolete, instead, just a plain 0 is used. Depending on the context, the compiler will do the right thing.

Why null is not defined in C++?

However, since NULL in C++ is defined as 0, you might start using 0 instead of NULL so as not to depend on whether a macro is defined or not. NULL is not defined as zero. A C++ compiler (and a C compiler), by convention, is required to treat a zero valued pointer as if it were the NULL pointer.

Why can a null pointer not be accessed?

Because a null pointer does not point to a meaningful object, an attempt to dereference (i.e., access the data stored at that memory location) a null pointer usually (but not always) causes a run-time error or immediate program crash. In C, dereferencing a null pointer is undefined behavior.


2 Answers

C 2011 Standard, online draft

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.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.
66) The macro NULL is defined in <stddef.h> (and other headers) as a null pointer constant; see 7.19.

The macro NULL is always defined as a zero-valued constant expression; it can be a naked 0, or 0 cast to void *, or some other integral expression that evaluates to 0. As far as your source code is concerned, NULL will always evaluate to 0.

Once the code has been translated, any occurrence of the null pointer constant (0, NULL, etc.) will be replaced with whatever the underlying architecture uses for a null pointer, which may or may not be 0-valued.

like image 71
John Bode Avatar answered Sep 18 '22 15:09

John Bode


WhozCraig wrote these comments to a now-deleted answer, but it could be promoted to a full answer (and that's what I've done here). He notes:

Interesting note: AS/400 is a very unique platform where any non-valid pointer is considered equivalent to NULL. The mechanics which they employ to do this are simply amazing. "Valid" in this sense is any 128-bit pointer (the platform uses a 128bit linear address space for everything) containing a "value" obtained by a known-trusted instruction set. Hard as it is to believe, int *p = (int *)1; if (p) { printf("foo"); } will not print "foo" on that platform. The value assigned to p is not source-trusted, and thus, considered "invalid" and thereby equivalent to NULL.

It's frankly startling how it works. Each 16-byte paragraph in the mapped virtual address space of a process has a corresponding "bit" in a process-wide bitmap. All pointers must reside on one of these paragraph boundaries. If the bit is "lit", the corresponding pointer was stored from a trusted source, otherwise it is invalid and equivalent to NULL. Calls to malloc, pointer math, etc, are all scrutinized in determining whether that bit gets lit or not. And as you can imagine, putting pointers in structures brings a whole new world of hurt on the idea of structure packing.


This is marked community-wiki (it's not my answer — I shouldn't get the credit) but it can be deleted if WhozCraig writes his own answer.

What this shows is that there are real platforms with interesting pointer properties.

There have been platforms where #define NULL ((void *)0) is not the usual definition; on some platforms it can be just 0, on others, 0L or 0ULL or other appropriate values as long as the compiler understands it. C++ does not like ((void *)0) as a definition; systems where the headers interwork with C++ may well not use the void pointer version.

I learned C on a machine where the representation for the char * address for a given memory location was different from the int * address for the same memory location. This was in the days before void *, but it meant that you had to have malloc() properly declared (char *malloc(); — no prototypes either), and you had to explicitly cast the return value to the correct type or you got core dumps. Be grateful for the C standard (though the machine in question, an ICL Perq — badged hardware from Three Rivers — was largely superseded by the time the standard was defined).

like image 42
2 revs Avatar answered Sep 18 '22 15:09

2 revs