The newsgroup, comp.lang.c, is plagued by an almost continuous discussion of whether we can or cannot use void as a return type for main. The ANSI standard says "no", which should be an end of it. However, a number of beginners' books on C have used void main(void) in all of their examples, leading to a huge number of people who don't know any better.
When people ask why using a void is wrong, (since it seems to work), the answer is usually one of the following:
This page demonstrates a system on which a void main(void) program will very likely cause problems in the third class above. Calling the program from a script may cause the script to die, whether or not its return code is checked. Calling it from a makefile may cause make to complain. Calling it from the command line may cause an error to be reported.
RISC OS is the native operating system of Acorn's range of ARM based computers. One of the facilities of this OS is a system variable, Sys$RCLimit. The value of this variable specifies the maximum value that a program may return to the OS without causing RISC OS itself to raise an error. The default value of this variable is set by the OS at 256. I'm not too sure what the intended function of this variable was, but it exists, and that's that.
Now, let's look at an example program using int main(void).
int main(void) { return 42; }Compiling it to ARM assembly language, using gcc (as an aside: Acorn's own C compiler reports a warning with void main(void) and converts it to an integer function returning zero) gives the following:
|main|: mov ip, sp stmfd sp!, {rfp, fp, ip, lr, pc} sub fp, ip, #4 cmps sp,sl bllt |x$stack_overflow| bl |___main| mov r0, #42 ldmdb fp, {rfp, fp, sp, pc}^
What happens with a void main function? Well, here's an example.
#includeThe program waits for a line of text from its standard input, nothing else. Again we compile it to assembler:char buf[1024]; void main(void) { (void)fgets(buf, 1024, stdin); }
|.LC0|: dcd |__iob| |.LC1|: dcd |buf| |main|: mov ip, sp stmfd sp!, {rfp, fp, ip, lr, pc} sub fp, ip, #4 cmps sp,sl bllt |x$stack_overflow| bl |___main| ldr r2, [pc, #|.LC0| - . - 8] mov r1, #1024 ldr r0, [pc, #|.LC1| - . - 8] bl |fgets| ldmdb fp, {rfp, fp, sp, pc}^ area |buf|, DATA, COMMON, NOINIT % 1024
Here's the result of compiling and running the program:
SCSI: void % gcc void.c -o void Drlink AOF Linker Version 0.28 30/07/95 SCSI: void % show Sys$RCLimit Sys$RCLimit : 256 SCSI: void % void I enter this line Return code too large SCSI: void %
And, in a script file:
SCSI: void % cat script void echo Finished SCSI: void % run script I enter this line Return code too large SCSI: void %
Note that the example above was a little contrived in order to make the final function call return a pointer. A better example where this could cause problems is one where the program uses printf to report a usage string > 256 characters long prior to returning or, worse still, one where the program uses printf to output data depending on user input. Depending on the length of the user's input text, the program may or may not cause an error which is solely due to the use of void as a return type for main.
So, if you want your software to be portable, please make main return int. It does matter.