前言
在C/C++程序中有时会见到采用诸如
void main()
等方式来声明主函数,很多人在主函数返回值的问题上也略显随意。经过查阅多版本的C、C++标准文档与相关书籍,我将我的结论与认识总结于此。不可避免地,其中可能包含我错误的认识,欢迎大家指正。main()函数的函数类型
关于
main()
的原型,C89/99/11以及C++98/03/11/14等标准给出的说法略有出入,尤其在早期标准中差异更为显著。然而,共同的,在任何一个版本的标准中,均未承认void main()
这种声明方式。首先可以得出结论:void main()
为错误写法,所有编译器都没有理由支持该种写法。
在K&R C与C89里,若函数没有显式声明返回类型,则默认是int
,因此在早期C程序中经常出现这样的主函数:1
2
3
4
5main()
{
// 函数体
return 0;
}
这种写法在早期标准中是被认可的,main()
等价于int main()
。但是,C99标准不再支持函数的int
类型的默认设置,因此该写法被废止,新的编译器不再允许此类main函数。
在C99/11标准中,明确定义了对于标准的main函数的两个原型:1
2int main(void) { /* ... */ }
int main(int argc, char *argv[]) { /* ... */ }
为了增强说服力,我在《C Primer Plus》(第六版)(该书以1999 ISO/ANSI作为标准)中找到了这样一段话:
如果浏览老版本的C代码,您将发现程序常常以:
main()
这种形式开始。C90标准勉强允许这种形式,但是C99标准不允许。因此即使您当前的编译器允许,也不要这么做。
您还将看到另一种形式:void main()
有些编译器允许这种形式,但是还没有任何标准考虑接受它。因而,编译器不必接受这种形式,并且许多编译器也不这样做。再者说,如果坚持使用标准形式,那么当您把程序从一个编译器移到另一个编译器时也不会有问题。
main()函数的形式参数
此部分C与C++略有差异
- C
int main()和int main(void)在C语言中是有区别的:1
2
3int main() { /* ... */ }
// 不等价于
int main(void) { /* ... */ }
在C语言中参数列表为空(即不提供参数列表也不为void),表示不提供参数数量和参数类型信息:1
2
3
4
5
6
7
8
9
10
11
void func() // 参数列表为空不代表不接受参数
{
print("Hello, world\n");
}
int main(void)
{
func(1,2,3,4); // 调用func(),并传递了参数
return 0;
}
因此在C中,main函数的参数部分应该以以下两种方式描述:1
2int main(void) { /* ... */ }
int main(int argc, char *argv[]) { /* ... */ }
不应该写:1
int main() { /* ... */ }
- C++
由于C和C++中对于函数参数列表的规则并不一致(C++中参数列表为空代表不接收任何参数)。所以C++中main的原型和ISO C也并不太一样。
在C++中,下面两种写法是完全等价的。1
2
3int main() { /* ... */ }
// 等价于
int main(void) { /* ... */ }
以上两种形式均符合标准。
main()函数的返回值
上文指出,main()
应以int类型定义,故需要返回一个int
类型的返回值到操作系统。
在早期标准中,主函数中的return 0;
是可以省略的,main()
最后如果没有返回值,则会自动return 0;
,但是记住,只有main函数是这样,其他函数不能省略return
。
自C99/C++98以来,主函数的返回值为强制,若漏掉了返回语句,大多数编译器会给出警告,但仍将编译程序。
return 0;
:一般用在主函数结束时,按照程序开发的一般惯例,表示成功完成本函数return -1;
:一般用在子函数结尾,按照程序开发的一般惯例,表示该函数失败
main()
必须要有返回值的原因是:在C和C++中使用return-statement都是将return的值作为参数来调用exit/std::exit来终止程序。
此外,返回值对于某些操作系统(包括DOS和UNIX)而言,具有实际的用途。
以Windows为例,编译以下程序:1
2
3
4
5/* test.c */
int main(void)
{
return 0;
}
在命令提示符下运行命令test && dir
,得到以下结果:1
2
3
4
5
6
7
8
9
10
11
12D:\code>test && dir
D:\code 的目录
2018/09/26 10:31 <DIR> .
2018/09/26 10:31 <DIR> ..
2018/09/26 10:29 35 test.c
2018/09/26 10:30 41,664 test.exe
2 个文件 41,699 字节
2 个目录 605,409,882,112 可用字节
D:\code>
test.exe正常结束后执行dir
指令,输出了目录列表。
若将第4行返回值由0改为-1:1
return -1;
再次执行test && dir
命令:1
2
3D:\code>test && dir
D:\code>
test.exe将-1返回给了操作系统,即程序异常结束,因此windows没有继续执行dir
打印目录列表。
总结一下,正常情况下main函数应以return 0;
结束,不能随意更改返回值。
结语
综上所述,一般情况下,C/C++程序的主函数都应该以如下方法编写:1
2
3
4
5int main(void) // void在C++中可省,C不建议省
{
// 函数体
return 0;
}
即使其他不标准的声明方法也许不会影响程序的正常编译、运行,但为了程序的可移植性与易维护性,我们应该养成良好的编码习惯,利人利己。
参考文献
[1] Stephen Prata 编著,《C Primer Plus》,人民邮电出版社,2005年,§2.2 §9.2 §B.5.
[2] Andrew Koenig 编著,《C陷阱与缺陷》,人民邮电出版社,2008年,§2.1 §7.1.
[3] Stephen Prata 编著,《C++ Primer Plus》,人民邮电出版社,2012年,§2.1 §2.4.