[net.lang.c] Is #define NULL 0L ok?

ok@edai.UUCP (Richard O'Keefe) (03/10/84)

One kind net.lang.c reader pointed out that Lint was JUSTIFIED
in its complaints about my passing NULL to functions expecting
a pointer argument.  What I hadn't realise was that stdio.h
defines
	#define	NULL 0
(I thought it was (char*)0.)  Now I know that there is no hope
of ever running the program I've been struggling with on a 16-
bit machine, the question is will it run on a machine with 32-
bit pointers but int=16 bits.  So I've changed my header file,
it now starts

	#include <stdio.h>
	#undef	NULL
	#define	NULL 0L

This works fine on the VAX, but then so did NULL=0.  Can any
reader with a ptr=32&int=16 C compiler tell me if this is ok
for such compilers?

PS: my request for an ALIGNOK directive to Lint had nothing
to do with *this* problem.

gwyn@brl-vgr.ARPA (Doug Gwyn ) (03/12/84)

NO NO NO

You MUST cast the 0 to the proper pointer type when passing it as an
actual argument to a function:

	foo( (char *)0 );

for example.  There is no other way of guaranteeing that the function
gets a pointer of the proper type.

tjt@kobold.UUCP (03/12/84)

Using:

	#include <stdio.h>
	#undef	NULL
	#define	NULL 0L

will fail on a machine with 16 bit pointers, 16 bit int's but 32-bit
longs (the pdp-11, for example).  On the pdp-11, defining NULL as 0L
will cause two words to be pushed on the stack for as a function
argument while the called routine will only be expecting one word for
that argument.

As has been pointed out too many times to count, it is impossible to
define a generic null pointer in C: you have to cast 0 to the pointer
type when passing it as an argument.  You can do this by including the
type cast in each use, or #define a null pointer for each pointer type
you use.
-- 
	Tom Teixeira,  Massachusetts Computer Corporation.  Westford MA
	...!{ihnp4,harpo,decvax}!masscomp!tjt   (617) 692-6200 x275

guy@rlgvax.UUCP (Guy Harris) (03/13/84)

> 	#include <stdio.h>
> 	#undef	NULL
> 	#define	NULL 0L

> This works fine on the VAX, but then so did NULL=0.  Can any
> reader with a ptr=32&int=16 C compiler tell me if this is ok
> for such compilers?

Yes, it works on our compiler.  However, "lint" will *still* yell at
you (it isn't complaining about the size of the object, it's complaining
about its type), it means the code won't work on a 16-bit machine (even
if it would fit) nor will it work on a machine where (to pick a possibly
strange example) pointers and "int"s are 32 bits while "long"s are 64 bits,
and it won't work on a machine where the representation of a null pointer
isn't a string of all zero bits.  Why not just run the code through "lint"
and read and heed its warnings?

	Guy Harris
	{seismo,ihnp4,allegra}!rlgvax!guy

tim@unc.UUCP (Tim Maroney) (03/14/84)

This reminds me -- another small change that the ANSI Standard committee
might want to make in C is to make NULL be a real synatctic object, so that
we don't have to do dumb-looking (and usually forgotten) things like:

foo( (char *)NULL );

After all, the use of NULL in software has become part of the de facto C
standard.
--
Tim Maroney, University of North Carolina at Chapel Hill
mcnc!unc!tim (USENET), tim.unc@csnet-relay (ARPA)

All opinions expressed herein are completely my own, so don't go assuming
that anyone else at UNC feels the same way.

msc@qubix.UUCP (Mark Callow) (03/14/84)

The situation as succintly as I can put it is:

1)	The C language definition (K&R) says that the *symbol* '0' may be
	used to represent a null pointer.

2)  	The compiler therefore has to identify places where '0' is being
	used as a null pointer (for example by identfying assignments to
	or comparisons with pointers) and it has to *replace it with* the
	actual value of a null pointer for the particular machine and the
	data type being pointed to.

3)	Given that there is no requirement (and no way) to inform the compiler
	of the types (or number) of arguments to an external function the
	compiler can't know that some argument to your function is a pointer.

	In the case of
	
		func( 0 );
		
	therefore,  the compiler can't intuit whether '0' is being used as a
	null pointer or in its more common usage as the symbol for the
	arithmetic value 0.

4)	The compiler assumes the more common usage so if the argument to
	*func* is actually a pointer you *must* give an explicit cast to
	the correct type of pointer.  For example you must say

		func( (char *)0 );
-- 
From the Tardis of Mark Callow
msc@qubix.UUCP,  decwrl!qubix!msc@Berkeley.ARPA
...{decvax,ucbvax,ihnp4}!decwrl!qubix!msc, ...{ittvax,amd70}!qubix!msc

hom@hocda.UUCP (H.MORRIS) (03/16/84)

A "real" NULL such that one can say foo(NULL) instead of
foo((char *)NULL) with perfect assurance implies that while
compiling the line foo(NULL) the cc knows something about the
arguments declared for the function foo.  That implies in turn
that either cc snoops around for the file containing the declaration
of foo - which gives you a language with a radically different
philosophy from C, or else within the file containing `foo(NULL)'
there is a declaration of the form:
return-type foo( (char *));
 instead of what is currently allowed:
return-type foo();
 (the former describes foo's arguments; the latter doesn't).
I heard somewhere that this is being considered.
	I am not passionate about whether function definitions which
describe the argument type are a good thing.  I feel strongly that
they should be optional so as to allow functions which take
variable argument lists like printf.  But just to point out that
without such a construct, you can't have foo(NULL) work always on
all machines when argument to foo is a pointer.
Hal MOrris ...hocad!hom