void main(void) - the Wrong Thing
来源:互联网 发布:java html生成器 编辑:程序博客网 时间:2024/05/22 10:59
http://users.aber.ac.uk/auj/voidmain.cgi
void main(void) - the Wrong Thing
The newsgroup, comp.lang.c, is plagued by an almost continuous discussion of whether we can or cannot usevoidas 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 usedvoid 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:
- Because the standard says so.
(To which the answer is usually of the form "but it works for me!") - Because the startup routines that call main could be assuming that the return value will be pushed onto the stack. Ifmain() does not do this, then this could lead to stack corruption in the program's exit sequence, and cause it to crash.
(To which the answer is usually of the form "but it works for me!") - Because you are likely to return a random value to the invokation environment. This is bad, because if someone wants to check whether your program failed, or to call your program from a makefile, then they won't be able to guarantee that a non-zero return code implies failure.
(To which the answer is usually of the form "that's their problem").
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 withvoid 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}^
The first six instructions are initialisation and stack checking. The final two return 42 to the library startup code. So, the return value ofmain is passed in R0. Note that the library startup code is expecting to call a function returning an integer, so will happily use the value returned in R0.
What happens with a void main function? Well, here's an example.
#include <stdio.h>char buf[1024];void main(void){(void)fgets(buf, 1024, stdin);}
The program waits for a line of text from its standard input, nothing else. Again we compile it to assembler:
|.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
Again, the first six instructions in main set things up. The next three set up the arguments for the call tofgets. Then we callfgets and return to the caller.stdio.h says thatfgets returns a pointer to the buffer. So, in this instance, what we are returning to the library startup code is a pointer tobuf. Under RISC OS, all C programs are mapped into memory at 0x8000. So, we will be returning a value to the OS which is > 32768 (hence, certainly > the default value ofSys$RCLimit). The OS then raises an error.
Here's the result of compiling and running the program:
SCSI: void % gcc void.c -o voidDrlink AOF Linker Version 0.28 30/07/95SCSI: void % show Sys$RCLimitSys$RCLimit : 256SCSI: void % voidI enter this lineReturn code too largeSCSI: void %
And, in a script file:
SCSI: void % cat scriptvoidecho FinishedSCSI: void % run scriptI enter this lineReturn code too largeSCSI: void %
The error interrupts the script before the second command is run.
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 ofvoid as a return type for main.
So, if you want your software to be portable, please makemain returnint. It does matter.
- void main(void) - the Wrong Thing
- void main(void) - the Wrong Thing
- void main(void) - the Wrong Thing
- void main(void) - the Wrong Thing
- void main(void)
- void main(void)用法
- main()、main(void)、int main()、int main(void)、void main()、void main(void)
- int main void main main
- main/int main/void main
- void main与int main(void)
- FAQ > What's the difference between... > main() / void main() / int main() / int main(void) / int main(int argc, char *argv[])
- int main (void)
- 关于void main
- void main()误区
- static void main
- void main()误区
- 不要用void main()
- public static void main
- Apache添加mod_python模块
- 编码 GBK 的不可映射字符
- hibernate4整合spring3.1出现java.lang.NoClassDefFoundError: Lorg/hibernate/cache/CacheProvider
- jquery 实现iframe 自适应高度
- 文件File的基本操作
- void main(void) - the Wrong Thing
- 设计模式六大原则(5):迪米特法则
- Linux下部署安装教程
- 输入一棵二叉树,求树的深度
- 2014高考英语听力,男约女终于成功了
- 傅里叶分析之掐死教程
- IOS 用封装API AsyncSocket进行网络通信
- 设计模式系列课程24之【备忘录模式】
- Java保留指定小数位数工具类