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