void main(void) - 错误的用法

        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,这样会做的更好。

        原文链接http://users.aber.ac.uk/auj/voidmain.shtml

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值