Because C uses a 'void' type to identify those functions which are really
procedures.
It further overloads 'void' in a function signature, to specify functions
(or procedures) with 0 parameters, rather than an unknown number.
I agree C could have maybe done more with 'void', after having invented it.
"Hysterical raisins."
Original C had no `void' type at all. A function returning no
value simply omitted specifying a return type (which formally declared
that it returned `int'), and the caller simply knew to ignore whatever
garbage happened to land in the conventional place for `int' results.
Also, malloc() et al. were usually declared as returning `char*'
("usually," because the usual suite of system-provided headers usually
had no malloc() declaration). This may be why we still see people
applying casts to malloc() results: In the days when the results
were `char*' and needed to be assigned to a `struct foo*', the cast
was in fact necessary.
A third thing: In original C, there was no way to describe a
function's parameter list to its callers. You simply said "This is
a function returning a `foobar'; read the documentation if you
want to know how to call it. (Oh, yeah, I'll write the documentation
Real Soon Now.)"
Along came the Committee that developed the ANSI Standard, and
they saw that "ignore the `int' that wasn't returned" was fragile, and
could even be burdensome for some implementations (they might need to
set aside a place for the non-existent result, or might need to use
up a CPU register to not hold it). They also wanted to fix up the
cast-malloc() mess, and to borrow the C++ idea of describing the
parameter lists in a way the compiler could use. And thus were born
the three uses of `void':
- You could declare a function as "returning `void'", which truly
means it returns nothing at all. (No, not even a vacuous value.)
Hooray! C got procedures that were recognizable as such.
- You could declare pointers to the non-instantiable `void' type,
and then you could introduce special rules for silent conversion of
such pointers to all other data pointer types. Hooray! All those
malloc() casts became unnecessary, *and* the compiler could still
diagnose failures to declare malloc() properly. (And a Standard
declaration was inserted into a brand-new header, too.)
- Ah, but the parameter lists were a bit of a problem. The empty
list `()' didn't really mean "no parameters," but "parameters in the
style of traditional C, that is, we don't know what they are or how
many." It would be nice to get rid of the traditional meaning of `()'
and co-opt it as meaning "no parameters," but this would invalidate
just about all the C code that had been written in the prior twenty-
odd years. Hence, a kludge: `()' retained its traditional meaning,
while `(void)' was invented to mean what `()' "should" have meant.
And that, O Best Beloved, is how the Ritchie's Child got his trunk.