[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: On the use of 0 or NULL, the discussion continues...

From: Bob Proulx
Subject: Re: On the use of 0 or NULL, the discussion continues...
Date: Thu, 28 Jun 2007 13:46:40 -0600
User-agent: Mutt/1.5.9i

Eric Blake wrote:
> #include <unistd.h>
> int main()
> {
>   return execl("ls", "Makefile", 0);
> }

Use of 'execl' is a good point.  It is not possible to prototype that
function such that an integer zero can be known by a standard compiler
as a pointer and so get automatic conversion into a pointer type.  It
is similar to setvbuf, strtok, select, but different in a critical
way.  Therefore the terminating zero pointer always needs a cast.
Also it should be a cast to char* and not void* if one is being
pedantic about the types.  However since void* will be coerced
automatically into a char* in C the cast is not needed in C.

This creates a subtle issue when using execl with C++.  In C the NULL
macro will usually be defined as equivalent to "(void*)0" and will be
a pointer type.  But in C++ becuase NULL cannot be defined to be a
pointer type then NULL is simply defined as 0 and so the following is
not correct for C++ code.

  return execl("ls", "Makefile", NULL);  // Incorrect in C++!

For C++ it must be one of the following:

  return execl("ls", "Makefile", (char*)0);
  return execl("ls", "Makefile", (char*)NULL);

And of course this latter expands to be:

  C:   return execl("ls", "Makefile", (char*)(void*)0);
  C++: return execl("ls", "Makefile", (char*)0);

I have often heard people say that using NULL avoids the need to use a
cast and so they prefer it.  But with execl and C++ a cast is still
required.  But execl is one of the very old calls and predates worries
about this type of thing.  Fortunately the number of routines in that
list that need to be known about specifically is very small.

The man page for execl says:

       The list of arguments must be terminated by a NULL pointer,
       and, since these are variadic functions, this pointer must be
       cast (char *) NULL.

I am sure that is because the man page is shared between C and C++ and
in C++ the cast is required.

In the standards docs:


All of the examples use "(char*)0" instead of NULL.  I assume this is
again so that the same documentation applies equally to C and C++.
There is no reference to "NULL" anywhere on that page.

> >  Here is another example.
> I prefer option 1,

But option 1 (aka "if (var1) ...") has an implied "!= 0" in the
expression.  I like != 0 and so I like option 1 very much too.  But if
someone takes the stance that pointers should always use NULL then I
think they would not like "if (ptrvar) ..." then because it is
basically the same as "!= 0".

> but will use option 3 when my company coding standards require no
> implicit conversions to bool.  I personally don't like option 2, but
> this is so much of a bike shed color discussion that I tend to
> ignore any differences between the three unless there is a
> consistency issue.

It is definitely a bike shed color discussion.  I try to ignore the
appearance differences when it really won't make any difference.
Generally I would always try to match the style of the surrounding
code even if I did not like it personally.

> Which is why C++0x is in the process of standardizing something very
> similar to gcc's __null via the proposed new keyword nullptr:
> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2214.pdf

Thanks for the pointer.  I have not been keeping up with the latest
discussions.  I have been ignoring C++ in particular of late.  It has
just been changing too rapidly for the casual observer to keep aware
of all of the issues.

In that paper I found one reasoning for making 0 not a pointer type
humorous.  "Remove embarrassments."  :-)

I find the proposal interesting in that it is one more thing that
pulls C++ apart to be different from C and will make it a little bit
harder for a C++ enthusiast to compile C code with a C++ compiler.  If
NULL (aka (void*)0 ) is no longer a pointer type in C++ then people
trying to compile source, say gnulib, with C++ will have a much more
difficult time of it.

Because C and C++ are different I have never liked the idea of using
the C++ compiler on C code and "dumbing down" the C code to work with
C++ in order to get C++ warnings.  Instead I prefer to use the C
compiler with all warnings enabled or to use additional code analysis
tools to get that information from the C code itself.

> > BTW... I don't feel the need to try to convince anyone.  If I did then
> Agreed.  And that's why the GNU Coding Standards intentionally leave some
> matters of style unspecified.  :)

As long as we are talking style one other thing that has always
annoyed me is the space after the function and before the parens.
(e.g. "foo (arg);" instead of "foo(arg);".)  While I am sure that
practice came from experience with lisp (which always separates the
function and the arguments with a space and seems fine to me there
with lisp syntax) it never seems natural to me in other languages.  It
seems that most other language styles prefer no space there and at
least one other language (ruby) codifies it in the language that the
space cannot be there!  Sigh.  Perhaps Fortran's complete denial that
whitespace exists in the input deck is the right way after all. :-)


reply via email to

[Prev in Thread] Current Thread [Next in Thread]