There should be _no_ difference in how a program runs, whether you use
"int main()" or "void main()". That only tells the compiler that the
program returns a value, that most operating systems use as the "return
or completion code".
Indeed. But what if this changes the calling sequence or function's
linker-level name?
The problem, you see, is that someone else -- over whom you have no
control -- has already written "int main()", in the code that calls
builds argc and argv and calls main() initially.
On typical boxes today, that code looks in part like this:
extern int main(int, char **);
...
exit(main(argc, argv));
Of course, the ANSI C standard requires that this work even if the
programmer wrote:
int main(void) {
so a less-typical box might actually have TWO startup routines, the
other looking like this:
extern int main(void);
...
exit(main());
Now suppose the C compiler uses a C++-style "name mangling" scheme
in order to distinguish between main(void) and main(int, char **).
The former compiles to 0$main$ and the latter to 2$i$ppc$main$.
At link time, this less-typical box scans the object files to see
whether the "main" symbol is 0$main$ or 2$i$ppc$main$, so as to
choose the correct call into main().
If you write something other than one of these two forms, then, your
program might fail to link.
Suppose that, instead of (or in addition to) name-mangling, we have
a stack-oriented machine in which main()'s return value is popped
and pushed (or no-op'ed) from the value stack to be passed to
exit(). If the value stack is empty at the initial call to main(),
and you use "void main()" (and if the compiler is doing name-mangling
you somehow manage to make it link despite not finding the right
name), then the startup routine's call to exit() (or exit() itself)
attempts to pop a value off an empty stack. The result is a runtime
exception when main() returns.
The latter may sound farfetched, but something remarkably similar
does happen on real implementations today if you manage to write code
of the form:
struct S { char a[100]; };
struct S main(int argc, char **argv) {
Typically one writes this accidentally, by mistakenly leaving off
the ";" at the end of the first line, and using "default int"
declarations that turn out not to be default int after all:
struct S {
char a[100];
} /* NOTE MISSING SEMICOLON */
main(int argc, char **argv) {
... code here using argc and/or argv ...
}
In this case, a number of compilers assume you "really meant":
void main(struct S *__secret_arg1, int argc, char **argv) {
...
/* returning a value assigns to *__secret_arg1, then returns */
}
so that argc and argv wind up having "peculiar values". (In fact,
on these systems today, argv seems to be junk or to contain the
environment variable list, and argc is some huge number. Yes,
I have debugged just such a problem.
)
The point of all this is simple enough: if you write "int main()",
a big guy with a large bat is metaphorically standing right behind
your compiler-vendor, ready to whack him in the head if he makes
your code fail because of this. But, if you write "void main()",
the guy with the bat will not do anything to your compiler-vendor,
because you failed to keep *your* part of the bargain.
The "bargain" in question is the C standard, which has lists of
programming constructs and behaviors and says (not quite literally)
"if you do only these things, your vendor must do only those things."
As long as the things you need done are things *every* ANSI-C vendor
*must* do, you have little to lose by sticking to the standard.
You may or may not think you have much to gain, but history suggests
that in fact you *do* have something to gain.
In other words, if you write "int main()", you are quite probably
helping yourself, and if you write "void main()", you are quite
probably hurting yourself.
Note that this is *not* true for *other* places you (as a programmer)
might completely ignore the ANSI C standard. For instance, given
that this thread is (for some mysterious reason) cross-posted to
rec.games.chess.computer, you might have a chess game in which you
want to draw graphics in a window. ANSI C does not give you a way
to do this -- so the cost/benefit equation now swings heavily the
other way: "Cost of not using standard C: unknown, probably not
zero but probably not huge. Benefit: can achieve goal." Compare
that to "void main": "Cost: unknown, probably not zero but probably
not huge. Benefit: none."
--
In-Real-Life: Chris Torek, Wind River Systems (BSD engineering)
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it
http://67.40.109.61/torek/index.html (for the moment)
Reading email is like searching for food in the garbage, thanks to