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