您的位置:首页 > 大数据 > 人工智能

void main(void) - 错误的用法

2008-08-25 13:16 567 查看
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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: