代码改变世界

【编写高质量代码:改善C++程序的150个建议 之 0.0】 不要让你的Main函数返回void

2012-01-12 15:33  凌云健笔  阅读(744)  评论(2编辑  收藏  举报

第1章 从C继承而来的

C和C++语言可以说是在所有编程语言中关系最为紧密的两个。在目标上,C++被定位为A Better C;在名称上,C++有一个乳名叫做“C with classes”;在语法上,C更是C++的一个子集,C++几乎支持C语言的全部功能。如果采用C++的方法来描述,以下的方式恰如其分:

1 class C{}; 
2 class CPlusPlus :public C {};

C++继承自C。

 正是这种难以割舍的紧密联系使得C/C++程序员必须对C有所重视。所以,本章就从C++的前身——C语言说起。

在开始这段学习旅程前,先分享一个只有程序员才明白的幽默: 有一次,她和他开玩笑的问:“我在你心里排第几?”他回头微笑着摸了摸她的头,用手指比划了个鸭蛋。她知道他在开玩笑,打了他一巴掌,尽管有些郁闷,但还是尽量避免流露出失望的神色。然而,她只是个文科生,她并不知道,也完全无法理解:在程序员的眼中,所有的数组、列表、容器的下标都是从0开始的。 所以,我们的建议也从0开始。

建议0:不要让你的Main函数返回void

同C程序一样,每个C++ 程序都包含一个或多个函数,而且必须有一个函数命名为main。每个函数都是由具有一定功能的语句序列组成的。操作系统将main作为程序入口,调用main函数来执行程序;main函数执行其语句序列,并返回一个值传给操作系统。在大多数系统中,main 函数的返回值用于说明程序的退出状态。如果返回0 ,则代表main函数成功执行完毕,程序正常退出。否则代表程序异常退出。 然而在编写C++程序入口函数main()的时候,很多Coder,特别是一些具有C基础的C++ Coder时经常会写出如下格式的main函数:

1 void main() 
2 {
3 // some code …
4 }

上述代码在VC++中是可以正确编译、链接、执行的。编译信息如下所示:

1>------ 已启动生成: 项目: MainCpp, 配置: Debug Win32------ 

1> mian.cpp

1> MainCpp.vcxproj -> G:\MainCpp\Debug\MainCpp.exe

========== 生成: 成功1 个,失败 0 个,最新 0 个,跳过 0 个==========

但是当你将代码放在Linux环境下,采用Gcc编译器进行编译时,你会吃惊地发现编译器抛出了如下的错误信息:

[develop@localhost ~] g++ main.cpp 

mian.cpp:2:错误:‘::main‘必须返回‘int

为什么同样的代码会出现两种不同的结果呢?这还是跨平台的C/C++语言吗?不要对C/C++的跨平台性产生质疑;之所以会这样,很大程度上要归结于市面上一些书的“误导”,以及微软VC++编译器main返回值问题的过分纵容。 在C和C++中,不接收任何参数也不返回任何信息的函数原型为“void f(void);”。所以很多人认为,如果不需要程序返回值时可以把main函数定义成void main(void)。然而这种想法是非常错误的!

有一点你必须明确:C/C++标准中从来没有定义过void main( )这样的代码形式。C++之父 Bjarne Stroustrup 在他的主页FAQ 中明确地写着这样的一句话:

在C++中绝对没有出现过void main(){/* ... */}这样的函数定义,在C语言中也是。

main 函数的返回值应该定义为int 类型,在C和 C++ 标准中都是这样规定的。在C99 标准中,规定只有以下两种定义方式是正确的①:

int main( void ) 
int main( int argc, char *argv[] )

在C++03中也给出了如下两种main函数的定义方式②:

int main() 
int main( int argc, char *argv[] )

虽然在C和C++标准中并不支持void main(),但在部分编译器中void main()依旧是可以通过编译并执行的,比如微软的VC++;由于微软产品的市场占有率与影响力很大,更是在某种程度上加剧了这种不良习惯的蔓延。但并非所有编译器都支持 void main(),gcc就站在了VC++的对立面,它是这一不良习气的坚定抵制者,它会在编译时就明确地给出一个错误。

如果你坚持在某些编译器中使用void main()这样的非标准形式的代码,那么当你把程序从一个编译器移植到另一个编译器时,你也要对可能出现的错误负责。

除了void mian()这样的不规范格式外,在C语言程序当中,尤其是一些老版本的C代码中,你还是会经常看到main()这样的代码形式。

在一些老的C标准诸如C90中,是支持main()这样的形式的。之所以这样,是因为在第一版的C语言中只有int一种数据类型,而不存在char、long、float、double等这些内置数据类型。既然只有int一种类型,那么就不必显式地为main函数表明返回类型了;在Brian W. Kernighan 和 Dennis M. Ritchie的经典巨著《The C programming Language 2e》中用的就是 main()。后来,在C语言的改进版中数据类型得到了扩充,为了能兼容以前的代码,于是标准委员会的那帮大牛们就做出了如下规定:不明确标明返回值的,默认返回值为int。在C99标准中,要求编译器对于main()这种用法至少要抛出一个警告。

main 函数返回值的作用,我们可以采用下面的方法加以验证。

首先,编写main.cpp文件,文件内容如下所示:

int main() 
{
return 0;
}

在Linux环境下,采用命令:

g++ main.cpp 

生成可执行文件a.out。然后,执行命令:

./a.out && ehco "success"

结果输出success。 修改上述程序:

int main() { return -1; }

做同样测试,无输出;
命令A && B中的&&类似于C++中的并操作(&&),如果A命令正确执行,接着就会执行命令B;如果A出现异常,则B不执行;通过以上分析表明当main()返回0时,a.out正确执行并返回;但是如果返回-1,程序就不能正常返回了。

最后,还得说明一下C++标准中一个“好坏难定”的规定:

A return statement in main has the effect of leaving the main function (destroying any objects with automatic storage duration) and calling exit with the return value as the argument. If control reaches the end of main without encountering a return statement, the effect is that of executingreturn 0;

                                                       ——ISO C++03 3.6.1 Main function

也就是说,如果函数执行到main结束处时没有遇到return语句,编译器会悄悄地隐式地为你加上return 0;,效果与返回0相同。之所以说这条规定“好”,是因为它让我们省去了多敲几个字的麻烦;但是又说它“不好”,是因为这样会让某些程序员忽视编译器代替他做出的那些劳动,而在思维中形成一种错误的认识:此函数可以无返回。

在应用这一规则时,你还得注意以下这两点:

 (1)main函数的返回类型是int,不是void或者其他类型。
 (2)该规则仅仅对main函数适用。
按照以上标准我们得到了一个完全合乎C/C++标准的最小化的完成C++程序: 

int main() {}

本人不推荐使用上述这条规则,建议还是加上return 0;,杜绝那些不必要误解的产生。

 

请记住:

要想保证程序良好的可移植性能,就要main函数返回int,而不是void。Remember That “void main(void)” isA Wrong Thing。强烈建议使用以下形式:

int main() 
{
// some processing code
return 0;
}

 

作者: 凌云健笔

出处:http://www.cnblogs.com/lijian2010/

版权:本文版权归作者和博客园共有
转载:欢迎转载,为了保存作者的创作热情,请按要求【转载】
要求:未经作者同意,必须保留此段声明;必须在文章中给出原文连接;否则必究法律责任