"do ... while ((NULL + 1) - 1);" -- valid C?
Chris Torek
chris at mimsy.UUCP
Fri Aug 11 19:01:17 AEST 1989
In article <940 at lakesys.UUCP> chad at lakesys.UUCP (D. Chadwick Gibbons) writes:
>... In most decent implementations, NULL is indeed defined as either
>0 or 0L.
Right.
>But this can't be, and isn't, true in all implementations,
No and yes: it could be, but it is not.
>... In many current implmentations, NULL is often defined as ((char *)0)
>since it is the only "safe" thing to do [meaning `the only way the vendor
>can keep the authors of bad code happy'].
This is both unsafe and wrong, even if it does keep such authors happy.
Consider: If we write
char *cp;
int *ip;
ip = cp;
the compiler must issue some kind of diagnostic (it says so in the
proposed ANSI C specification, and it says in K&R-1 that this operation
is machine-dependent, and all quality compilers do indeed generate a
warning). This situation does not change if we write
ip = (char *)ip;
It does change if we write instead
ip = (int *)(char *)ip;
which puts the value in ip through two transformations (from
pointer-to-int to pointer-to-char, then from pointer-to-char to
pointer-to-int), and these two together are required to reproduce
the original value (this is something of a special case).
So: consider what happens if some implementer has wrongly put the line
#define NULL ((char *)0)
in <stdio.h> and <stdarg.h> and so forth, and we write
ip = NULL;
The compiler sees
ip = ((char *)0);
which, as far as the type system is concerned, is identical to
ip = cp;
---that is, it is machine dependent, and requires a warning. We can
(probably) eliminate the warning% by adding a cast:
ip = (int *)NULL;
which expands to
ip = (int *)((char *)0);
On *most* machines, this `just happens' to work. But if we look very
closely at the language definition, we find that it is not *required*
to work. The version of this that is required to work is instead
ip = (int *)(char *)(int *)0;
We are not allowed (outside of machine-dependent code) to change a
pointer-to-char into a pointer-to-int unless the pointer-to-char itself
came into existence as the result of a cast from a pointer-to-int. The
only way to *create* a nil-pointer-to-int in the first place is to
write (int *)0, or (in the proposed ANSI C) (int *)(void *)0.
Of course, the actual definition of NULL in <stdio.h> and <stdarg.h>
and so on is provided per machine, so if
int *ip = (int *)(char *)0;
`just happens' to work on that machine, the vendor could get away
with it. But
int *ip = NULL;
is guaranteed to work *without* generating warnings on any machine
where NULL is correctly defined, and one should not have to write
int *ip = (int *)NULL;
just to avoid getting warnings---nor should the compiler be silent
about code like
int *ip; char *cp; ip = cp;
The rest of <940 at lakesys.UUCP> is correct.
-----
% The (probably) in eliminating warnings refers to the fact that
a compiler can warn about anything it pleases:
% cc -o foo foo.c
cc: Warning: relative humidity and barometer pressure
indicate that thunderstorms are likely
cc: Warning: your shoelace is untied
cc: Warning: this code looks ugly
cc: Warning: your mother wears army boots
cc: Warning: Hey! Keep away from me with that axe!
cc: Warning: Ack! No, wait, I di(*&1to01llk
--
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