I think so too, although the differene is pretty marginal (in my opinion).
I think if you follow Keith's example a bit further, the "language no
worse" argument begins to break down:
void *p=&foo;
void *q=&bar;
void r=*p; /* legal given your arguments */
void s=*q; /* also legal */
if( r == s ) {
/* MUST be true, unless there is more than one value of type void,
but what's the point? */
}
I do not see this as a problem. In a language "like C but with
sizeof(void)==0 and in which the one value of type void, which
occupies no bits, appears to be zero at all times" (which I have
proposed before), we get:
r == s
r == 0
r != 3
Values of type "void" can be used in any integer or boolean context
and simply appear to be zero. Values can be converted to "void",
by cast or assignment; this discards all their bits.
One can also do:
void *p = &foo;
...
p++; /* but afterward, p==&foo */
Unless I'm mistaken, void r=*p would require the language to define
conversion from values of all types to this magical single value of
void.
It is not very "magical", it is just 0. The conversion would be
defined for integers, at least, and maybe for pointers as well (a
la C99's boolean type), but probably not for struct and union.
... void t=3; /* ridiculous */
And yet, in C as it stands today, we can write:
(void) 3;
which is just as ridiculous. Why can we *cast* to void, but not
*assign* to void?
The main weirdness with variables of type void (in this not-quite-
but-almost-C language) is that, because sizeof(void) is 0, given:
void a;
int b;
void c;
int d;
it is possible to have &a == &b, &a == &c, and/or &a == &d (but
&b != &d, so if &a==&b then &a!=&d). (This same situation occurs
today in GNUC, though, using arrays of size 0.)