USE_NET新闻组一直苦恼于一个问题的讨论,我们能否用void作为一个main的返回类型,ANSI标准说不能,然而,大量的关于C的启蒙书中的例子都使用了void main (void),这让许多人感觉不知该如何是好。
当有人问为什么使用void是错误的时候,(即使它能正常工作),回答往往是下面中的一个:
因为标准这么说(这种回答通常是针对这这种问题"它能正常工作!")
因为调用main()的启动程序可以被认为是入栈,如果main()不这么做,在程序退出时将导至stack corruption的问题,并且 引发冲突。(这种回答通常是针对这这种问题"它能正常工作!")
因为你可能给调用环境返回一个随机值,这是很糟糕的,因为如果有人想要检测你的程序是否失败了,或者从一个makefile中调用你的程序,那么它们将不能保证非零的返回值就是失败。(这样的回答通常是针对这种问题"那是他们的问题")。
       这里我们举一个系统的例子去证明void main(void)程序在上面第三条里将要引起的问题。从一个脚本调用程序可能引起脚本的崩溃。不管它的返回码是否被检测到。从一个makefile调用它可能引起make的问题。从命令行调用它可能引起一个错误报告。
RISC OS 是一种本地的操作系统,这个系统的方便之处是有一个系统变量Sys$RCLimit.这个变量的值是用来指定一个程序可以返回到系统的最大值,这个变量的默认值被系统设置为256.我不能确认这个变量的目的,但是它是确定存在的。
现在,让我们看一个用int main(void)的例子程序
int main(void)
{
return 42;
}
把它翻译成汇编语言,用gcc(Acorn自己的C编译会报告一个警告,并把它转换成一个返回值为0的整型函数):
|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}^
第六个指令是初始化和堆栈检测,最后两个返回42到库的启动码,所以main的返回值被传递到R0.标记库启动码将要去调用一个整型的返回函数,所以能够使用R0的返回值。
void main function发生了什么?好的,这儿是一个例子。
#include <stdio.h>
       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        第六个指令是启动,下面的三个为fgets的调用设置参数,那么我们调用fgets并且返回到调用者。stdio.h中说fgets返回一个指针到缓存,所以,在这个实例中,我们返回到库启动码的是一个指向buf的指针,在RISC OS中,所有C程序被映射到内存地址0x8000.所以,我们将返回一个 > 32768 的值到操作系统中,(因此,大于Sys$RCLimit默认的值).系统产生错误。
这儿是编译和运行程序的结果:
        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 %    
在第二个命令运行之前,错误中断了程序
注意,上面的例子是一个小的人为的目的去使最终函数调用返回一个指针。一个更好的例子是程序用printf:
string > 256时也会返回错误,依赖用户输入字符的长度,程序是否可能返回一个错误在于用void作为main类型的返回
所以,如果你想要你的软件更有笑,请让main返回int,这样会做的更好。
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/jia_xiaoxin/archive/2008/08/25/2826868.aspx