Definition of NULL

Erik Trulsson ertr1013 at student.uu.se
Sat May 2 16:50:53 UTC 2009


On Sat, May 02, 2009 at 04:59:03PM +0100, Andrew Brampton wrote:
> I'm writing a C++ Kernel Module, and one thing that has been bugging
> me is the kernel's definition of NULL.

Is the use of C++ inside the kernel really supported?  I don't think so,
but I could be wrong.

> 
> sys/sys/_null.h (in CURRENT):
> 
> #if defined(_KERNEL) || !defined(__cplusplus)
> #define NULL    ((void *)0)
> #else
> #if defined(__GNUG__) && defined(__GNUC__) && __GNUC__ >= 4
> #define NULL    __null
> #else
> #if defined(__LP64__)
> #define NULL    (0L)
> #else
> #define NULL    0
> #endif  /* __LP64__ */
> #endif  /* __GNUG__ */
> #endif  /* _KERNEL || !__cplusplus */
> 
> >From what I've read online the definition of NULL in C is (void *)0,
> whereas in C++ it should be 0, or 0L (on 64bit machines).

Not quite.  Any of those (as well as a whole bunch more) are legal
definitions of NULL in C.  NULL is defined (in the C standard) to be a null
pointer constant.  A null pointer constant is defined as a constant integer
expression with value zero, or such an expression cast to (void*). (In C++
it the cast to (void*) is not allowed.)
This means that it would be perfectly legal (but of dubious utility) to have
NULL defined as (5*5L+('1'-'0')-26) for example.

The decision to define NULL as 0 or 0L or ((void*)0) is pretty much just a
question of which buggy programs one wishes to break, or hide the bugs in.
A correct C program should work regardless of which of those is used.


> 
> Now, my C++ kernel module is built with _KERNEL definited, like any
> other C kernel module. This leads to NULL being defined incorrectly.
> 
> So I have a question and two suggestions. Firstly, why is the #if
> defined(_KERNEL) in _null.h? Is it to stop userland application
> applications picking up this definition? Or for another reason?

Perhaps to stop people from mistakenly using C++ inside the kernel?


> 
> and two, how about we change the first line of _null.h so that we use
> a && instead of a || like so:
> #if defined(_KERNEL) && !defined(__cplusplus)
> 
> That should ensure the definition is correct. Or, a more radical
> approach, we could remove the check for _KERNEL, since I can't figure
> out why it is needed and do something like:
> 
> #if defined(__GNUG__) && defined(__GNUC__) && __GNUC__ >= 4
> # define NULL    __null
> #elif !defined(__cplusplus)
> # define NULL    ((void *)0)
> #elif defined(__LP64__)
> # define NULL    (0L)
> #else
> # define NULL    0
> #endif
> 
> That way, if we are using GCC 4+ we use their __null definition,
> otherwise if we are not c++ we use the standard (void *)0, and then if
> we are 64bit we use 0L, and finally anything else uses 0. A quick
> amd64 kernel compile seems to allow my new definition

If you want to keep things simple you could just define NULL as 0
everywhere, and see what bugs are exposed that way.

> 
> I hope this makes sense, and I welcome all feedback.
> Andrew


-- 
<Insert your favourite quote here.>
Erik Trulsson
ertr1013 at student.uu.se


More information about the freebsd-hackers mailing list