[comp.os.minix] NULL

nfs@notecnirp.Princeton.EDU (Norbert Schlenker) (11/13/89)

In article <1347@gould.doc.ic.ac.uk> dds@cc.ic.ac.uk (Diomidis Spinellis) writes:
> appeals to authority omitted
>...
>3. Will defining NULL as ((void *)0) enable some WRONG programs to
>   successfuly run on some architectures and C implementations?	[yes]
>...
>Yes.  In some architectures and some C implementations WRONG programs
>will work.  Here is an example for this:
>...
> example of broken code that works correctly if NULL is ((void *) 0) omitted

The argument is specious.  It is not hard to come up with broken code, similar
to that of the article, which works when NULL is defined as 0 and not when it
is defined as ((void *) 0).

All things considered, I think it will be more portable to define NULL as a
simple 0.  I don't think that appeals to Harbison and Steele are germane,
and the draft ANSI standard leaves it (purposely) vague.  It's just simpler
to use 0.

Norbert

keie@cs.vu.nl (Ed Keizer) (11/16/89)

I would like to add the following opinions to the current
debate on NULL pointer constants. The context I use the
current, and probably final, version of the proposed ANSI C standard.

1 - It is up to the creator of a C implementation whether the NULL
    pointer constant is defined as one of

	0
	0L
	(void *) 0

    One might even define NULL as `5-5', as that is a constant expression
    with the value 0.

    I added a part section 3.2.2.3 of the december 1988 version of
    the pANS C standard that clearly states this.

2 - Thus it is a question of taste and convenience which form to choose.
    Taste is hard to measure, but convenience is a usable criterium.
    It follows from this criterium that an implementor
    should try to avoid pitfalls for the unwary.

    The pitfalls in the use of the null pointer constant lie in the
    passing of null pointers to routines without prototypes. In all
    other places the implementation can cast NULL to the appropiate type.
    `0' or `0L' passed as an argument may have a different
    representation from null pointers. Therefore it is wise to define
    NULL as `(void *)0'.
    The problem is less severe in Standard C because all library routines
    have prototypes there.

    I have added a few paragraphs from the Rationale accompanying the
    proposed C standard for further elucidation.

3-  Chris Torek's argument for `0' instead of any other form is a invalid.
    Basicly his, and others people's, solution to the problem
    of null pointers
    with different representations for different types is to always cast
    NULL to the proper type. This solution will work for ALL definitions
    of NULL allowed by the C standard. And thus offers NO argument contra
    or pro NULL defined as `0'.

4-  The opinion of Henry Spencer that a cast of 0 to any other pointer
    type than `void *' is illegal and pointless, is incorrect.
    It is not illegal, it is implementation defined and non-portable.
    I would be very surprised though to see an implementation that produces
    different result for the expressions `(char *)(void *)0' and
    `(char *)0'.
    I fully agree with Henry Spencer's  opinion that all this is a
    concession to badly written code.

5-  I disagree with Diomidis Spinellis's opinion a C implementor should
    go to lengths to punish people for writing bad code. On the contrary,
    it is in the `Spirit of C' to not break existing code. A user
    should be warned against non-portable code by an implementation,
    but not punished harshly.  
    
Finally, which definition of NULL to choose is definitely up to the
creator of a C implementation. Programs should simply use NULL, and
never define it. If a C implementation behaves with (void *)
as specified in the ANSI standard that implementor would be wise
to define NULL as `(void *)0'. I do not express any opinions on
the wisest choice for NULL on C implementations that do not
conform to the proposed C standard.

Some extracts:	
Proposed C standard: paragraph 3.2.2.3, page 38

   An integral constant expression with the value 0,
   or such an expression cast to type `void *',
   is called a `null pointer constant'.
   If a null pointer constant is assigned to or compared for
   equality to a pointer,
   the constant is converted to a pointer of that type.
   Such a pointer, called a `null pointer',
   is guaranteed to compare unequal to a pointer to any object or function.

Rationale paragraph 3.3.9, page 47

   In pointer comparisons, one of the operands may be of type `void *'.
   In particular, this allows NULL, which can be defined as `(void~*)0',
   to be compared to any object pointer.
   
Rationale paragraph 4.1.5, page 73

   NULL can be defined as any null pointer constant.
   Thus existing code can retain definitions of NULL as 0 or 0L,
   but an implementation may choose to define it as `(void~*)0';
   this latter form of definition is convenient on architectures
   where the pointer size(s) do(es) not equal the size of any integer type.
   It has never been wise to use NULL in place of an arbitrary pointer
   as a function argument, however,
   since pointers to different types need not be the same size.
   The library avoids this problem by providing special macros for the
   arguments to signal,
   the one library function that might see a null function pointer.

Ed Keizer
Vrije Universiteit
Amsterdam

Member of ISO/IEC JTC1/SC22/WG14-C

The opinions stated here are mine and not those of WG14.

henry@utzoo.uucp (Henry Spencer) (11/19/89)

In article <4555@math.cs.vu.nl> keie@cs.vu.nl (Ed Keizer) writes:
>4-  The opinion of Henry Spencer that a cast of 0 to any other pointer
>    type than `void *' is illegal and pointless, is incorrect.

There is nothing wrong with casting 0 to any pointer type; however, this
is not a legal definition for NULL.  4.1.5 says NULL must be a "null
pointer constant".  This is *not* an informal term with whatever meaning
an implementation chooses to give it:  it is precisely defined, in 3.2.2.3,
as "an integral constant expression with the value 0, or such an expression
cast to type `void *'".

>5-  I disagree with Diomidis Spinellis's opinion a C implementor should
>    go to lengths to punish people for writing bad code. On the contrary,
>    it is in the `Spirit of C' to not break existing code...

Moreover, it is of considerable practical importance.  The benefit of
implementing a compiler for a standard language, rather than one of your
own design, is being able to compile programs written by other people.
I personally would have been pleased to see the "goto" statement left out
of C as unnecessary and trouble-prone, but given that it *is* in the
language, I do *not* want to see it removed from the C compilers I use.
This would unnecessarily break too much (ugly) code, code that does work
and that I don't want to have to fix just now.  Tolerance is a necessity
for a practical compiler.
-- 
A bit of tolerance is worth a  |     Henry Spencer at U of Toronto Zoology
megabyte of flaming.           | uunet!attcan!utzoo!henry henry@zoo.toronto.edu

kjh@pollux.usc.edu (Kenneth J. Hendrickson) (06/22/91)

*** BUG FIX ***

In /usr/include/stdio.h, #define NULL 0
In /usr/include/*.h (all others), #define NULL ((void *)0)

stdio.h should be updated asap.

If I'm wrong about this, or if this will break anything, please let me
know.

-- 
favourite oxymorons:   student athlete, military justice, mercy killing
Ken Hendrickson N8DGN/6       kjh@usc.edu      ...!uunet!usc!pollux!kjh

david@doe.utoronto.ca (David Megginson) (06/22/91)

In article <33822@usc.edu> kjh@pollux.usc.edu (Kenneth J. Hendrickson) writes:
>*** BUG FIX ***
>
>In /usr/include/stdio.h, #define NULL 0
>In /usr/include/*.h (all others), #define NULL ((void *)0)
>
>stdio.h should be updated asap.
>
>If I'm wrong about this, or if this will break anything, please let me
>know.

You are absolutely right. When I made this change, I was able to
compile cdungeon (ie. Zork) in 16-bit mode with c68 on the Atari ST.
Before, I had to use Gnu C in 32-bit mode. Let's make this change
official...


David


-- 
////////////////////////////////////////////////////////////////////////
/  David Megginson                      david@doe.utoronto.ca          /
/  Centre for Medieval Studies          meggin@vm.epas.utoronto.ca     /
////////////////////////////////////////////////////////////////////////

laverman@cs.rug.nl (Bert Laverman) (06/24/91)

In article <33822@usc.edu> kjh@pollux.usc.edu (Kenneth J. Hendrickson) writes:
>*** BUG FIX ***
>
>In /usr/include/stdio.h, #define NULL 0
>In /usr/include/*.h (all others), #define NULL ((void *)0)
>
>stdio.h should be updated asap.
>
>If I'm wrong about this, or if this will break anything, please let me
>know.
There is some controversy on this. ACK is a real K&R compiler, and thus
((int)0) (sorry for the explicit int, but I want to make a point) is the
only acceptable NULL 'anypointer'. For ANSI C (void *) pointers can be
used as generic pointers, in the sense that any pointer is casted to this
one without complaint. (The other way around is dangerous, and _should_
give a warning)
  ACK C knows about the void type, but it doesn't really understand
NULL as ((void *)0). It generates endless amounts of warnings about
'illegal pointer combination's.

  Now, since ACK is K&R, the integer NULL is correct.
  BUT (a big one): 68k ACK uses pointers of 32, and ints of 16 bits.
Giving an integer NULL as parameter to a procedure will get you in
trouble (to say the least).

Isn't there a commandment on this? something like:
  - thou shalt cast al parameters of a procedure to the expected
    type lest horrible thing happen.
I don't remember the correct wording, but it's not for fun!

Greetings, Bert
-- 
#include <std/disclaimer>

  Bert Laverman,  Dept. of Computing Science, Groningen University
  laverman@cs.rug.nl			bert@arrakis.nl.mugnet.org

adamd@rhi.hi.is (Adam David) (06/24/91)

In <33822@usc.edu> kjh@pollux.usc.edu (Kenneth J. Hendrickson) writes:

>*** BUG FIX ***

>In /usr/include/stdio.h, #define NULL 0
>In /usr/include/*.h (all others), #define NULL ((void *)0)

That is the way it is defined in my copy. It is broken like this.
The compiler warns about redefine NULL unless stdio.h is the last
file to be included. I have seen systems where the NULL defines
are all 0 or all ((void *)0) but it seems odd to have them mixed.
Of course there should be more use of '#ifndef NULL' exclusions.

Could someone please give an authoritative answer on this.

--
Adam David.
(adamd@rhi.hi.is)

paula@bcsaic.UUCP (Paul Allen) (06/24/91)

In article <33822@usc.edu> kjh@pollux.usc.edu (Kenneth J. Hendrickson) writes:
>*** BUG FIX ***
>
>In /usr/include/stdio.h, #define NULL 0
>In /usr/include/*.h (all others), #define NULL ((void *)0)
>
>stdio.h should be updated asap.
>
>If I'm wrong about this, or if this will break anything, please let me
>know.

I think you're wrong, but I'm not enough of a wizard to say so with
authority.  In my archives, I find two articles explaining why NULL
is zero.  One, posted by Cris Torek back in early 1988, is quite long
and has been reposted at least once in response to continuing calls
to change the definition of NULL.  The other, by Steve Jenkins of
Caltech/JPL, is much more concise, just as convincing, and refers
interested parties to the FAQ for comp.lang.c.  Apparently, the C
wizards have been discussing this question for years, and have
concluded that the only correct thing to do is to define NULL as
the integer consant zero and cast it to an appropriate pointer type
when it is used.

Does anybody out there have a copy of the comp.lang.c Frequently-
Asked-Questions list?  If so, would you please post the section
dealing with NULL so that we may all benefit from the wisdom of the
experts?  I'd do it myself, but I must admit I've never been able
to muster the patience to wade through c.l.c.  :-)

Paul Allen





-- 
------------------------------------------------------------------------
Paul L. Allen                       | pallen@atc.boeing.com
Boeing Advanced Technology Center   | ...!uw-beaver!bcsaic!pallen

geels@cs.vu.nl (Arnold Geels) (06/25/91)

paula@bcsaic.UUCP (Paul Allen) writes:

>In article <33822@usc.edu> kjh@pollux.usc.edu (Kenneth J. Hendrickson) writes:
>>*** BUG FIX ***
>>
>>In /usr/include/stdio.h, #define NULL 0
>>In /usr/include/*.h (all others), #define NULL ((void *)0)
>>
>>stdio.h should be updated asap.
>>
>>If I'm wrong about this, or if this will break anything, please let me
>>know.


>Does anybody out there have a copy of the comp.lang.c Frequently-
>Asked-Questions list?  If so, would you please post the section
>dealing with NULL so that we may all benefit from the wisdom of the
>experts?  I'd do it myself, but I must admit I've never been able
>to muster the patience to wade through c.l.c.  :-)

One grep on /usr/spool/news/comp/lang/c/* did the job :-)

Note: The c.l.c. FAQ list is copyrighted.  See notice at end.

	From: scs@adam.mit.edu (Steve Summit)
	Newsgroups: comp.lang.c
	Subject: Answers to Frequently Asked Questions (FAQ) on comp.lang.c
	Date: 2 Jun 91 21:08:35 GMT
	Expires: 1 Jul 91 04:00:00 GMT

(stuff deleted)

The questions answered here are divided into several categories:

      1. Null Pointers
      2. Arrays and Pointers
      3. Order of Evaluation
      4. ANSI C
      5. C Preprocessor
      6. Variable-Length Argument Lists
      7. Lint
      8. Memory Allocation
      9. Structures
     10. Declarations
     11. Boolean Expressions and Variables
     12. Operating System Dependencies
     13. Stdio
     14. Style
     15. Miscellaneous (Fortran to C converters, YACC grammars, etc.)

Herewith, some frequently-asked questions and their answers:


Section 1. Null Pointers

1.   What is this infamous null pointer, anyway?

A:   The language definition states that for each pointer type, there is
     a special value -- the "null pointer" -- which is distinguishable
     from all other pointer values and which is not the address of any
     object.  That is, the address-of operator & will never yield a null
     pointer, nor will a successful call to malloc.  (malloc returns a
     null pointer when it fails, and this is a typical use of null
     pointers: as a "special" pointer value with some other meaning,
     usually "not allocated" or "not pointing anywhere yet.")

     A null pointer is conceptually different from an uninitialized
     pointer.  A null pointer is known not to point to any object; an
     uninitialized pointer might point anywhere (that is, at some random
     object, or at a garbage or unallocated address).  See also
     questions 46, 52, and 82.

     As mentioned in the definition above, there is a null pointer for
     each pointer type, and the internal values of null pointers for
     different types may be different.  Although programmers need not
     know the internal values, the compiler must always be informed
     which type of null pointer is required, so it can make the
     distinction if necessary (see below).

     References: K&R I Sec. 5.4 pp. 97-8; K&R II Sec. 5.4 p. 102; H&S
     Sec. 5.3 p. 91; ANSI Sec. 3.2.2.3 p. 38.

2.   How do I "get" a null pointer in my programs?

A:   According to the language definition, a constant 0 in a pointer
     context is converted into a null pointer at compile time.  That is,
     in an initialization, assignment, or comparison when one side is a
     variable or expression of pointer type, the compiler can tell that
     a constant 0 on the other side requests a null pointer, and
     generate the correctly-typed null pointer value.  Therefore, the
     following fragments are perfectly legal:

          char *p = 0;
          if(p != 0)

     However, an argument being passed to a function is not necessarily
     recognizable as a pointer context, and the compiler may not be able
     to tell that an unadorned 0 "means" a null pointer.  For instance,
     the Unix system call "execl" takes a variable-length, null-
     pointer-terminated list of character pointer arguments.  To
     generate a null pointer in a function call context, an explicit
     cast is typically required:

          execl("/bin/sh", "sh", "-c", "ls", (char *)0);

     If the (char *) cast were omitted, the compiler would not know to
     pass a null pointer, and would pass an integer 0 instead.  (Note
     that many Unix manuals get this example wrong.)

     When function prototypes are in scope, argument passing becomes an
     "assignment context," and most casts may safely be omitted, since
     the prototype tells the compiler that a pointer is required, and of
     which type, enabling it to correctly cast unadorned 0's.  Function
     prototypes cannot provide the types for variable arguments in
     variable-length argument lists, however, so explicit casts are
     still required for those arguments.  It is safest always to cast
     null pointer function arguments, to guard against varargs functions
     or those without prototypes, to allow interim use of non-ANSI
     compilers, and to demonstrate that you know what you are doing.

     Summary:

          Unadorned 0 okay:        Explicit cast required:

          initialization           function call,
                                   no prototype in scope
          assignment
                                   variable argument in
          comparison               varargs function call

          function call,
          prototype in scope,
          fixed argument

     References: K&R I Sec. A7.7 p. 190, Sec. A7.14 p. 192; K&R II
     Sec. A7.10 p. 207, Sec. A7.17 p. 209; H&S Sec. 4.6.3 p. 72; ANSI
     Sec. 3.2.2.3 .

3.   What is NULL and how is it #defined?

A:   As a matter of style, many people prefer not to have unadorned 0's
     scattered throughout their programs.  For this reason, the
     preprocessor macro NULL is #defined (by <stdio.h> or <stddef.h>),
     with value 0 (or (void *)0, about which more later).  A programmer
     who wishes to make explicit the distinction between 0 the integer
     and 0 the null pointer can then use NULL whenever a null pointer is
     required.  This is a stylistic convention only; the preprocessor
     turns NULL back to 0 which is then recognized by the compiler (in
     pointer contexts) as before.  In particular, a cast may still be
     necessary before NULL (as before 0) in a function call argument.
     (The table under question 2 above applies for NULL as well as 0.)

     NULL should _only_ be used for pointers; see question 8.

     References: K&R I Sec. 5.4 pp. 97-8; K&R II Sec. 5.4 p. 102; H&S
     Sec. 13.1 p. 283; ANSI Sec. 4.1.5 p. 99, Sec. 3.2.2.3 p. 38,
     Rationale Sec. 4.1.5 p. 74.

4.   How should NULL be #defined on a machine which uses a nonzero bit
     pattern as the internal representation of a null pointer?

A:   Programmers should never need to know the internal
     representation(s) of null pointers, because they are normally taken
     care of by the compiler.  If a machine uses a nonzero bit pattern
     for null pointers, it is the compiler's responsibility to generate
     it when the programmer requests, by writing "0" or "NULL," a null
     pointer.  Therefore, #defining NULL as 0 on a machine for which
     internal null pointers are nonzero is as valid as on any other,
     because the compiler must (and can) still generate the machine's
     correct null pointers in response to unadorned 0's seen in pointer
     contexts.

5.   If NULL were defined as follows:

          #define NULL (char *)0

     wouldn't that make function calls which pass an uncast NULL work?

A:   Not in general.  The problem is that there are machines which use
     different internal representations for pointers to different types
     of data.  The suggested #definition would make uncast NULL
     arguments to functions expecting pointers to characters to work
     correctly, but pointer arguments to other types would still be
     problematical, and legal constructions such as

          FILE *fp = NULL;

     could fail.

     Nevertheless, ANSI C allows the alternate

          #define NULL (void *)0

     definition for NULL.  Besides helping incorrect programs to work
     (but only on machines with homogeneous pointers, thus questionably
     valid assistance) this definition may catch programs which use NULL
     incorrectly (e.g. when the ASCII  NUL character was really
     intended).

6.   I use the preprocessor macro

          #define Nullptr(type) (type *)0

     to help me build null pointers of the correct type.

A:   This trick, though popular in some circles, does not buy much.  It
     is not needed in assignments and comparisons; see question 2.  It
     does not even save keystrokes.  Its use suggests to the reader that
     the author is shaky on the subject of null pointers, and requires
     the reader to check the #definition of the macro, its invocations,
     and _all_ other pointer usages much more carefully.

7.   Is the abbreviated pointer comparison "if(p)" to test for non-null
     pointers valid?  What if the internal representation for null
     pointers is nonzero?

A:   When C requires the boolean value of an expression (in the if,
     while, for, and do statements, and with the &&, ||, !, and ?:
     operators), a false value is produced when the expression compares
     equal to zero, and a true value otherwise.  That is, whenever one
     writes

          if(expr)

     where "expr" is any expression at all, the compiler essentially
     acts as if it had been written as

          if(expr != 0)

     Substituting the trivial pointer expression "p" for "expr," we have

          if(p)      is equivalent to                 if(p != 0)

     and this is a comparison context, so the compiler can tell that the
     (implicit) 0 is a null pointer, and use the correct value.  There
     is no trickery involved here; compilers do work this way, and
     generate identical code for both statements.  The internal
     representation of a pointer does _not_ matter.

     The boolean negation operator, !, can be described as follows:

          !expr      is essentially equivalent to     expr?0:1

     It is left as an exercise for the reader to show that

          if(!p)     is equivalent to                 if(p == 0)

     "Abbreviations" such as if(p), though perfectly legal, are
     considered by some to be bad style.

     See also question 68.

     References: K&R II Sec. A7.4.7 p. 204; H&S Sec. 5.3 p. 91; ANSI
     Secs. 3.3.3.3, 3.3.9, 3.3.13, 3.3.14, 3.3.15, 3.6.4.1, and 3.6.5 .

8.   If "NULL" and "0" are equivalent, which should I use?

A:   Many programmers believe that "NULL" should be used in all pointer
     contexts, as a reminder that the value is to be thought of as a
     pointer.  Others feel that the confusion surrounding "NULL" and "0"
     is only compounded by hiding "0" behind a #definition, and prefer
     to use unadorned "0" instead.  There is no one right answer.
     C programmers must understand that "NULL" and "0" are
     interchangeable and that an uncast "0" is perfectly acceptable in
     initialization, assignment, and comparison contexts.  Any usage of
     "NULL" (as opposed to "0") should be considered a gentle reminder
     that a pointer is involved; programmers should not depend on it
     (either for their own understanding or the compiler's) for
     distinguishing pointer 0's from integer 0's.

     NULL should _not_ be used when another kind of 0 is required, even
     though it might work, because doing so sends the wrong stylistic
     message.  (ANSI allows the #definition of NULL to be (void *)0,
     which will not work in non-pointer contexts.)  In particular, do
     not use NULL when the ASCII null character (NUL) is desired.
     Provide your own definition

          #define NUL '\0'

     if you must.

     Reference: K&R II Sec. 5.4 p. 102.

9.   But wouldn't it be better to use NULL (rather than 0) in case the
     value of NULL changes, perhaps on a machine with nonzero null
     pointers?

A:   No.  Although symbolic constants are often used in place of numbers
     because the numbers might change, this is _not_ the reason that
     NULL is used in place of 0.  Once again, the language guarantees
     that source-code 0's (in pointer contexts) generate null pointers.
     NULL is used only as a stylistic convention.

10.  I'm confused.  NULL is guaranteed to be 0, but the null pointer is
     not?

A:   When the term "null" or "NULL" is casually used, one of several
     things may be meant:

     1.   The conceptual null pointer, the abstract language concept
          defined in question 1.  It is implemented with...

     2.   The internal (or run-time) representation of a null pointer,
          which may or may not be all-bits-0 and which may be different
          for different pointer types.  The actual values should be of
          concern only to compiler writers.  Authors of C programs never
          see them, since they use...

     3.   The source code syntax for null pointers, which is the single
          character "0".  It is often hidden behind...

     4.   The NULL macro, which is #defined to be "0" or "(void *)0".
          Finally, as a red herring, we have...

     5.   The ASCII null character (NUL), which does have all bits zero,
          but has no relation to the null pointer except in name.

     This article always uses the phrase "null pointer" (in lower case)
     for sense 1, the character "0" for sense 3, and the capitalized
     word "NULL" for sense 4.

11.  Why is there so much confusion surrounding null pointers?  Why do
     these questions come up so often?

A:   C programmers traditionally like to know more than they need to
     about the underlying machine implementation.  The fact that null
     pointers are represented both in source code, and internally to
     most machines, as zero invites unwarranted assumptions.  The use of
     a preprocessor macro (NULL) suggests that the value might change
     later, or on some weird machine.  Finally, the distinction between
     the several uses of the term "null" (listed above) is often
     overlooked.

     One good way to wade out of the confusion is to imagine that C had
     a keyword (perhaps "nil", like Pascal) with which null pointers
     were requested.  The compiler could either turn "nil" into the
     correct type of null pointer, when it could determine the type from
     the source code (as it does with 0's in reality), or complain when
     it could not.  Now, in fact, in C the keyword for a null pointer is
     not "nil" but "0", which works almost as well, except that an
     uncast "0" in a non-pointer context generates an integer zero
     instead of an error message, and if that uncast 0 was supposed to
     be a null pointer, the code may not work.

12.  I'm still confused.  I just can't understand all this null pointer
     stuff.

A:   Follow these two simple rules:

     1.   When you want to refer to a null pointer in source code, use
          "0" or "NULL".

     2.   If the usage of "0" or "NULL" is an argument in a function
          call, cast it to the pointer type expected by the function
          being called.

     The rest of the discussion has to do with other people's
     misunderstandings, or with the internal representation of null
     pointers, which you shouldn't need to know.  Understand questions
     1, 2, and 3, and consider 8 and 11, and you'll do fine.

13.  Given all the confusion surrounding null pointers, wouldn't it be
     easier simply to require them to be represented internally by
     zeroes?

A:   If for no other reason, doing so would be ill-advised because it
     would unnecessarily constrain implementations which would otherwise
     naturally represent null pointers by special, nonzero bit patterns,
     particularly when those values would trigger automatic hardware
     traps for invalid accesses.

     Besides, what would this requirement really accomplish?  Proper
     understanding of null pointers does not require knowledge of the
     internal representation, whether zero or nonzero.  Assuming that
     null pointers are internally zero does not make any code easier to
     write (except for a certain ill-advised usage of calloc; see
     question 52).  Known-zero internal pointers would not obviate casts
     in function calls, because the _size_ of the pointer might still be
     different from that of an int.  (If "nil" were used to request null
     pointers rather than "0," as mentioned in question 11, the urge to
     assume an internal zero representation would not even arise.)

14.  Seriously, have any actual machines really used nonzero null
     pointers?

A:    "Certain Prime computers use a value different from all-
      bits-0 to encode the null pointer.  Also, some large
      Honeywell-Bull machines use the bit pattern 06000 to encode
      the null pointer."

                 -- Portable C, by H. Rabinowitz and Chaim Schaap,
                 Prentice-Hall, 1990, page 147.

     The "certain Prime computers" were the segmented 50 series, which
     used segment 07777, offset 0 for the null pointer, at least for
     PL/I.  Later models used segment 0, offset 0 for null pointers in
     C, necessitating new instructions such as TCNP (Test C Null
     Pointer), evidently as a sop to all the extant poorly-written C
     code which made incorrect assumptions.

     The Symbolics Lisp Machine, a tagged architecture, does not even
     have conventional numeric pointers; it uses the pair <NIL, 0>
     (basically a nonexistent <object, offset> handle) as a C null
     pointer.

Section 2. Arrays and pointers

	(lots 'n' lots of very good stuff deleted)

Acknowledgements

Thanks to Sudheer Apte, Dan Bernstein, Joe Buehler, Raymond Chen,
Christopher Calabrese, James Davies, Norm Diamond, Ray Dunn, Stephen M.
Dunn, Bjorn Engsig, Ron Guilmette, Doug Gwyn, Tony Hansen, Joe
Harrington, Guy Harris, Blair Houghton, Kirk Johnson, Andrew Koenig,
John Lauro, Christopher Lott, Tim McDaniel, Evan Manning, Mark Moraes,
Francois Pinard, randall@virginia, Pat Rankin, Rich Salz, Chip
Salzenberg, Paul Sand, Doug Schmidt, Patricia Shanahan, Peter da Silva,
Joshua Simons, Henry Spencer, Erik Talvola, Clarke Thatcher, Chris
Torek, Ed Vielmetti, Larry Virden, Freek Wiedijk, and Dave Wolverton,
who have contributed, directly or indirectly, to this article.  Special
thanks to Karl Heuer, and particularly to Mark Brader, who (to borrow a
line from Steve Johnson) have goaded me beyond my inclination, and
frequently beyond my endurance, in relentless pursuit of a better FAQ
list.

                                             Steve Summit
                                             scs@adam.mit.edu
                                             scs%adam.mit.edu@mit.edu
                                             mit-eddie!adam!scs

This article is Copyright 1988, 1990, 1991 by Steve Summit.
It may be freely redistributed so long as the author's name, and this
notice, are retained.
The C code in this article (vstrcat, error, etc.) is public domain and
may be used without restriction.

HBO043%DJUKFA11.BITNET@cunyvm.cuny.edu (Christoph van Wuellen) (06/25/91)

We had endless discussions on NULL last year, so let me summarize.

#define NULL 0 is correct, the faulting code is wrong. POINT.

BUT, if you want to compile those large amount of broken code, you are free
to #define NULL (void *)0 in your PRIVATE COPY of the header files.

C.v.W.

ns@csd.cri.dk (Nick Sandru) (06/25/91)

Exerpt from FAQ posting in comp.lang.c:

---
Section 1. Null Pointers

[...]

3.   What is NULL and how is it #defined?

A:   As a matter of style, many people prefer not to have unadorned 0's
     scattered throughout their programs.  For this reason, the
     preprocessor macro NULL is #defined (by <stdio.h> or <stddef.h>),
     with value 0 (or (void *)0, about which more later).  A programmer
     who wishes to make explicit the distinction between 0 the integer
     and 0 the null pointer can then use NULL whenever a null pointer is
     required.  This is a stylistic convention only; the preprocessor
     turns NULL back to 0 which is then recognized by the compiler (in
     pointer contexts) as before.  In particular, a cast may still be
     necessary before NULL (as before 0) in a function call argument.
     (The table under question 2 above applies for NULL as well as 0.)

     NULL should _only_ be used for pointers; see question 8.

     References: K&R I Sec. 5.4 pp. 97-8; K&R II Sec. 5.4 p. 102; H&S
     Sec. 13.1 p. 283; ANSI Sec. 4.1.5 p. 99, Sec. 3.2.2.3 p. 38,
     Rationale Sec. 4.1.5 p. 74.

---

I will post the whole article if there is interest for it.


Nick Sandru

--
.signature waiting at the entry signal

gert@targon.UUCP (Gert Kanis) (06/26/91)

In article <57132@nigel.ee.udel.edu> (Christoph van Wuellen) writes:
>We had endless discussions on NULL last year, so let me summarize.
>
>#define NULL 0 is correct, the faulting code is wrong. POINT.
>
>C.v.W.

Well, but still .. why have different definitions ?
As, the original poster stated:

In article <33822@usc.edu> kjh@pollux.usc.edu (Kenneth J. Hendrickson) wrote:
>
>In /usr/include/stdio.h, #define NULL 0
>In /usr/include/*.h (all others), #define NULL ((void *)0)
>

Whatever is the best choice but why not the same in *all* header files?
Or even better define it only once
  (I suppose historical reasons prohibit that)

BTW: (void *)0 would be OK in ANSI-C.
--
Gert Kanis, AP SWZ SWP                          +----------------------+
Siemens Nixdorf Information systems             | I do not represent   |
P.O.box 29,  4130 EA Vianen, Netherlands.       | anyone elses opinion.|
E-mail: outside Europe: kanis.via@sni-usa.com   +----------------------+
Europe: gert@targon.UUCP  Alternative: kanis.via@sni.de

jmason2@gpu.utcs.utoronto.ca (Jamie Mason) (06/27/91)

	You have *nothing* to say.  This thread is worth *nil*.  This
discussion is de*void* of any useful insight.  Please discontinue 
this lack-of-discussion. :-) :-)

Jamie  ...  Lurker in the Process Table
Written On  Thursday, June 27, 1991  at  01:27:15am EDT

evans@syd.dit.CSIRO.AU (Bruce.Evans) (06/27/91)

In article <33822@usc.edu> kjh@pollux.usc.edu (Kenneth J. Hendrickson) writes:
>*** BUG FIX ***
>
>In /usr/include/stdio.h, #define NULL 0
>In /usr/include/*.h (all others), #define NULL ((void *)0)
>
>stdio.h should be updated asap.
>
>If I'm wrong about this, or if this will break anything, please let me
>know.

The redefinition of NULL in stdio.h is to avoid about 1000 incorrect warnings
from the standard compiler. The standard compiler does not really understand
void *.
-- 
Bruce Evans		evans@syd.dit.csiro.au

chip@tct.com (Chip Salzenberg) (06/28/91)

According to evans@syd.dit.CSIRO.AU (Bruce.Evans):
>In article <33822@usc.edu> kjh@pollux.usc.edu (Kenneth J. Hendrickson) writes:
>>In /usr/include/stdio.h, #define NULL 0
>
>The redefinition of NULL in stdio.h is to avoid about 1000 incorrect warnings
>from the standard compiler. The standard compiler does not really understand
>void *.

Then the other headers should be changed to match.

There's no reason for inconsistency among /usr/include/*.h.
-- 
Chip Salzenberg at Teltronics/TCT     <chip@tct.com>, <uunet!pdn!tct!chip>
 "I want to mention that my opinions whether real or not are MY opinions."
             -- the inevitable William "Billy" Steinmetz