Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 2 May 2009 18:35:35 +0200
From:      Erik Trulsson <ertr1013@student.uu.se>
To:        Andrew Brampton <brampton+freebsd-hackers@gmail.com>
Cc:        freebsd-hackers@freebsd.org
Subject:   Re: Definition of NULL
Message-ID:  <20090502163535.GA17027@owl.midgard.homeip.net>
In-Reply-To: <d41814900905020859q4faff431p8819aaf38dfe9e78@mail.gmail.com>
References:  <d41814900905020859q4faff431p8819aaf38dfe9e78@mail.gmail.com>

next in thread | previous in thread | raw e-mail | index | archive | help
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@student.uu.se



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20090502163535.GA17027>