为什么main函数的默认返回值是0而不是EXIT_SUCCESS?

24

ISO 1998 C++标准规定,在main函数中不显式使用return语句等同于使用return 0。但如果实现有不同的"无错误"代码标准,例如-1,该怎么办?

为什么不使用标准宏EXIT_SUCCESS,它将根据实现替换为0-1或任何其他值?

C++似乎强制规定程序的语义,这不是语言的作用,语言应该只描述程序的行为。此外,在"错误"返回值方面情况不同:只有EXIT_FAILURE是标准的"错误"终止标志,没有明确的值,比如"1"。

这些选择的原因是什么?

9个回答

36

main()返回零基本上与您要求的内容相同。 从main()返回零不一定要向主机环境返回零。

来自C90 / C99 / C ++ 98标准文档:

如果status的值为零或EXIT_SUCCESS,则会返回实现定义的成功终止状态的形式。


4
仅澄清一下,这是针对exit()函数的规定,3.6.1:5指出从main函数返回的效果是离开main函数并调用exit()。所以,是的,你是正确的。 :) - jalf
1
换句话说,零和EXIT_SUCCESS是等价的返回值,因此默认返回哪一个标准要求的并不重要。 - Rob Kennedy
非常有趣,这意味着c++标准不强制要求主机的“成功代码”。所以从c++程序返回“0”并不能保证主机系统会接收到“0”,这意味着c++ return语句的行为可能与程序员指定的不同:“return 0”在某些实现中可能被“替换”为“return 1”? - Pragmateek
1
@Serious - 请记住,某个特定的环境可能甚至不会像Unix那样使用数字返回代码。如果有任何不再是好奇心的东西,我会感到惊讶,但例如,我真的不知道在使用JCL来控制程序执行的大型机环境中会发生什么。 - Michael Burr
4
@Serious: 但是更直接地回答你的问题——如果一个程序的执行环境期望数字1代表成功,数字0代表失败,那么从主函数返回值"return 0"可能会将程序退出代码设为1。而从主函数返回值"return EXIT_FAILURE"可能会将程序退出代码设为0。但我认为这种情况比较少见,因为C语言和Unix将数字0解释为成功的方式已经相当有影响力了。 - Michael Burr
显示剩余2条评论

18

实际上,return 0 并不一定会返回0!我引用C标准来解释这个问题,因为这是我最熟悉的。

关于 main() 中的 return:

5.1.2.2.3 程序终止

如果 main 函数的返回类型与 int 兼容,那么从 main 函数的初始调用返回等同于使用 main 函数返回的值作为参数调用 exit 函数;

关于 exit():

7.20.4.3 exit函数
梗概

#include <stdlib.h>
void exit(int status);

[...]
最后,控制权返回给宿主环境。如果status的值为零或者EXIT_SUCCESS,则会返回一个实现定义的形式表示成功终止的状态。


总是很高兴看到有人以易懂的方式解释标准。不过,能够在字面上选择零和EXIT_SUCCESS之间的区别等同于使用两个可能存在冲突定义。我这样想对吗? - xtofl
5
这个冲突的根源在哪里?使它正常工作是编译器的责任。最简单的方法是使用“#define EXIT_SUCCESS 0”,但这只是其中一种选择。 - MSalters
@Bastien:谢谢,你的评论完善了Michael的解释。 - Pragmateek

5

标准只是确定了当没有明确设置时必须是什么值。开发人员可以显式地设置返回值,也可以假定默认值的适当语义。我认为该语言并不试图强加任何语义给开发人员。


默认值不应由C++层确定,而应由系统确定。例如,如果程序首先是用C++编写的,则“0”将是标准成功代码;然后,如果它被重写为另一种语言,其中“1”是标准默认成功代码,它将破坏使用它的其他程序/用户的行为。而如果这两种语言都有一个宏EXIT_SUCCESS,那么它将由主机系统管理,所有东西都将正常工作。该宏将由编译器在系统上替换为其值:“posix”为“0”,其他为“1”... - Pragmateek

4

在所有的POSIX系统以及我所知道的所有系统中,0都是标准(成功)退出代码!我认为自Unix诞生以来就一直是这样。因此,出于这个原因,我会这么说。

你知道有哪些不同的系统吗?


3
在我看来,这不是问题所在:如果有任何系统偏爱不同的值,并且语言定义了一个成功的主返回值,那么这将使该语言在该系统上冲突。此外,你不能通过举例来证明一个定理。 - xtofl
2
"EXIT_STATUS的值可能与0不同,实际上在某个时间点上,在VAX/VMS上确实是如此。" - xtofl
"0" 作为成功标志是一种“事实上”的标准,这是真的。但是将其作为 C++ 的标准会强制主机系统使用它以实现“ISO 兼容性”。而使用标准常量如 EXIT_SUCCESS 可以保证语义上的“一切正常”与实现细节“0 表示成功,1 表示失败...”不耦合。 - Pragmateek

3

OS/360及其后续版本使用数字退出代码,其中0通常表示成功,4表示警告(例如生成警告消息的编译器),8表示错误,12表示特别严重的错误(例如无法打开SYSPRINT,即标准输出单元)。


3

在C语言和Unix中,0是成功的返回代码,正整数则表示错误。这种方案的选择是因为通常人们并不关心程序成功的原因,只关心它是否成功执行。另一方面,程序失败的方式有很多种,人们经常对此感兴趣。因此,使用一个标量值来表示成功,使用一系列值来表示错误是有意义的。使用正整数是C语言中省内存的约定,因为它们允许将错误代码定义为无符号整型。


1
计算机语言标准规定了使用该语言编写的程序应该做什么以及会发生什么。在这种情况下,C和C++标准规定返回0表示成功,还有其他一些规定。
语言实现允许程序在特定的实现上运行。实现者的工作是找出如何使I/O按照标准工作,或者给操作系统提供正确的结果代码。
程序执行的操作和操作系统看到的操作不必相同。所有必要的是,程序在给定的操作系统上按照标准工作。

1
通过浏览 cstdlib,我得到了两行代码:
#define EXIT_SUCCESS 0
#define EXIT_FAILURE 1

所以EXIT_SUCCESS等于0EXIT_FAILURE等于1,这意味着它并不重要。在Linux(OpenSuse)上检查结果相同。

3
说得严谨一些:这些定义仅适用于您的平台,另一个平台可能使用不同的约定;尽管我认为它们现在是普遍适用的。 :) (注:原文中的“defines”指的是代码中的宏定义) - Pragmateek
@Pragmateek 当然是的。这段代码来自Windows,但我认为Linux应该是一样的。 不过,我会从Linux和Android中读取,看看最终结果如何。 - набиячлэвэли

0
如果你也在想为什么成功的错误代码是0而不是其他值,我想补充一下可能是出于历史性能原因,因为与0比较会稍微快一些(我认为在现代架构中可能与任何数字相同),通常你不会检查特定的错误代码,只需检查是否成功或任何错误(因此使用最快的比较方式是有意义的)。

1
我不认为使用0作为成功指示器的原因是这个 - 我相信原因是通常有多种失败的方式,因此需要更多的失败代码。 - Michael Burr
没错,但这并不与我所说的相矛盾。如果ERROR_SUCCESS是1(或其他值),您仍然有所有其他数字来指示不同类型的失败。 - fortran

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接