Header problems

Chris Torek chris at mimsy.UUCP
Wed Mar 9 12:00:26 AEST 1988


>In article <7412 at brl-smoke.ARPA> gwyn at brl.arpa (Doug Gwyn) writes:
>>The implementor should put something like the following in each header:
>>	#define NULL 0

0) right

In article <3351 at chinet.UUCP> dag at chinet.UUCP (Daniel A. Glasser) writes:
>Your use of NULL === 0 promotes unportable code,

1) wrong

>On machines were sizeof int != sizeof(void *), the above definition will
>not work on older style function calls (without prototypes) or in var-arg
>situations.

2) poorly stated.  Incorrect code, such as the following:

	main { f(NULL); exit(0); }		/* wrong */
	f(s) char *s; { if (s != NULL) printf("%s\n", s); }

will indeed fail on such machines.  Correct code, acheived by changing
the first line to

	main { f((char *)NULL); exit(0); }	/* right */

will work properly with `#define NULL 0'.  Similar incorrect code will,
on some machines, fail no matter what the definition of NULL.  Leaving
out the prototype (where available) or the cast is an error; making it
appear to work is, I claim, a disservice.

>A better way to do it, in each place you want to define NULL, is:
> 	#ifndef	NULL
> 	#define	NULL	((void *)0)
> 	#endif

The dpANS legislates that this must work, again with the proviso that
the source code be correct (prototypes and/or casts present
everywhere).  The type (void *) does not exist in many pre-dpANS
compilers, hence I claim this definition is not as good.  All it does
is hide the old Vax-era errors on some other machines.  It does not
fix them.

>What the C language guarentees is not that 0===NULL, but that a constant 0
>can be assigned/compared to a pointer without warning or error regardless
>of pointer representation and compare as equal to the NULL pointer.

Correct (although I think it is better stated as `... compare as equal
to a nil pointer of the type of the first pointer').

>In cases where the compiler is unable to determine if an int or type *
>is being passed, 0 is passed as an int.  The use of the name NULL in the
>preprocessor does not affect this.

Also correct.  The solution, however, is to provide the context via
casts and/or prototypes, not to use (void *), which (if it exists at
all) may not have the same representation as, e.g., (int *) (and in
fact does not on several existing machines).  The following code is
incorrect:

	#undef NULL
	#define NULL ((void *)0)
	main() { f(NULL); exit(0); }		/* wrong */
	f(p) int *p; { if (p != NULL) *p = 11; }

(whether it appears to work on your machine is irrelevant).  This
version is correct:

	#undef NULL
	#define NULL 0
	main() { f((int *)NULL); exit(0); }	/* right */
	f(p) int *p; { if (p != NULL) *p = 11; }

Finally, note that in this last example, NO SINGLE DEFINITION OF NULL
can make the two lines marked `wrong' correct:

	main() {
		f1(NULL);	/* wrong */
		f2(NULL);	/* wrong */
		exit(0);
	}

	f1(cp) char *cp; { if (cp != NULL) *cp = 'a'; }
	f2(dp) double *dp; { if (dp != NULL) *dp = 2.2; }

The only way to fix this last example is by adding prototypes and/or
casts.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris at mimsy.umd.edu	Path:	uunet!mimsy!chris



More information about the Comp.lang.c mailing list