我应该从main()函数中返回EXIT_SUCCESS还是0?

170

这是一个简单的问题,但我看到的答案却不一:C++程序的主函数应该返回0还是EXIT_SUCCESS

#include <cstdlib>
int main(){return EXIT_SUCCESS;}

或者

int main(){return 0;}

它们是完全相同的吗?EXIT_SUCCESS 只应与 exit() 一起使用吗?

我认为 EXIT_SUCCESS 是更好的选择,因为其他软件可能希望将零视为失败,但我也听说如果你返回 0,编译器可以将其更改为不同的值。


这解答了你的问题吗?https://dev59.com/JnM_5IYBdhLWcg3w3nbz - Blastfurnace
2
这个关于C90的答案(https://dev59.com/7HVC5IYBdhLWcg3wtzkQ#207992)解释了标准——`0`和`EXIT_SUCCESS`都被解释为成功。 - ta.speot.is
9个回答

207

EXIT_FAILURE,无论是在main中的return语句中还是作为exit() 的参数,在C或C++程序中都是唯一可移植的指示失败的方式。exit(1)例如在VMS上实际上可能会发出成功终止信号。

如果你在程序失败时要使用EXIT_FAILURE,那么当它成功时最好使用EXIT_SUCCESS,仅出于对称性的考虑。

另一方面,如果程序从不发出失败信号,则可以使用0EXIT_SUCCESS。标准保证两者都能表示成功完成。(虽然EXIT_SUCCESS可能具有除0之外的值,但在我听说的每个实现中,它的值都等于0。)

使用0有一个小优点,即在C中不需要#include <stdlib.h>或在C++中不需要#include <cstdlib>(如果您使用return语句而不是调用exit()),但是对于任何规模的程序,您都将直接或间接地包含stdlib。

就此而言,在1999年开始的C标准中,以及所有版本的C++中,达到main()函数结尾时会隐式执行return 0;,因此您可能不需要显式使用0EXIT_SUCCESS。(但至少在C中,我认为显式的return 0;是更好的风格。)

有人问到OpenVMS。我已经很久没用了,但据我所记,奇数状态值通常表示成功,而偶数值表示失败。C语言的实现将0映射为1,因此return 0;表示正常终止。其他值保持不变传递,因此return 1;也表示正常终止。EXIT_FAILURE会具有非零的偶数值。


1
如果我理解你最后一段的意思正确,那么当exit(0)映射到退出状态1时,如何实现OpenVMS的POSIX实用程序? - user824425
4
@Rhymoid:这是由C指定的,而不是POSIX。 - Keith Thompson
1
@DeanP:0EXIT_SUCCESS不能保证具有相同的值(我在我的答案中提到了这一点),但它们都表示成功终止。如果您还使用EXIT_FAILURE,则EXIT_SUCCESS在风格上更好,但exit(0)也可以。 - Keith Thompson
2
这是个人的(出于明确的动机),但我喜欢使用“return(0)”(或!= 0),因为shell脚本“$?”兼容性(大多数Unix程序返回“$?”= 0表示成功)。 - André A. G. Scotá
2
@AndréA.G.Scotá:POSIX保证EXIT_SUCCESS==0。(而且在return语句中不需要括号。个人认为,它们让它看起来太像函数调用了。) - Keith Thompson
显示剩余4条评论

33

没关系,两者是一样的。

C++标准引用:

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


19
对于编译器而言并不重要,但从风格的角度来看却很有可能会有所影响。 - celtschk
2
@celtschk:风格问题是基于感知的,也就是说非标准化,因此这不算作差异。你只能拿苹果和苹果比较,而不能拿苹果和梨子比较。 - Alok Save
3
EXIT_SUCCESS == 0 不能保证一定成立,但也没有什么不应该成立的理由。 - Keith Thompson
@KeithThompson:为什么没有保证 EXIT_SUCCESS == 0?请更清楚地解释一下。 - Destructor
2
@PravasiMeet:一个系统可能有多个表示成功的值。 - Keith Thompson
2
功能胜于形式,但清晰度胜于功能。我可以从专业经验告诉你,在编程中风格非常重要。 - user824425

18

根据定义,0是一个神奇的数字。EXIT_SUCCESS几乎普遍等于0,这很幸运。那么为什么不只返回/退出0呢?

exit(EXIT_SUCCESS);的含义非常清楚。

另一方面,exit(0)在某些方面上是反直觉的。对于不熟悉shell行为的人来说,他们可能会认为0 == false == bad,就像C中的其他用法一样。但并不是这样——在这种特殊情况下,0 == success == good。对于大多数有经验的开发者来说,这不会是一个问题。但为什么要因为没有任何理由而让新手困惑呢?

简而言之 - 如果有一个定义好的常量可用于你的神奇数字,几乎没有理由不使用该常量。它更易搜索、通俗易懂,而且不会花费你任何代价。


3
我认为你对人们期望0自动变成坏的看法是不正确的。非常多的API使用0表示成功,非0表示失败,即使在stdlib中也是如此。例如:stdlib(fclose()setvbuf()等),POSIX(listen()pthread_create()pipe()等),以及许多其他库(例如OpenGL [glGetError()],zlib [deflate()/inflate()/...],SDL [SDL_CreateWindowAndRenderer()/...]等)。 - Tim Čas
3
当然,还有其他情况下会把0用作“成功”的表示,但他对于这种用法容易产生混淆是正确的。 - Paul Wintz

12

这是一个无休止的故事,反映了“互操作性和可移植性最重要”的限制(和神话)。

程序返回什么值来表示“成功”,应该由接收该值的人(操作系统或调用程序的进程)定义,而不是由语言规范定义。

但程序员喜欢以“可移植的方式”编写代码,因此他们发明了自己的模型来定义“操作系统”概念的符号返回值。

现在,在一个多对多的场景中(许多语言用于编写针对许多系统的程序),语言约定的“成功”与操作系统约定的“成功”之间的对应关系(没有人可以保证始终相同)应该由特定目标平台的库的具体实现处理。

但很不幸,当 C 语言部署时(主要用于编写 UNIX 内核),这些概念并不那么清晰,因此有大量的书籍写着“return 0 表示成功”,因为在当时有 C 编译器的操作系统上是正确的。

从那时起,就从未对如何处理这种对应关系进行清晰的标准化。C 和 C++ 有它们自己的“返回值”定义,但没有人保证有适当的操作系统翻译(或者更好地说:没有编译器文档说明它)。如果UNIX-LINUX和Windows的话,0表示成功,并且这覆盖了90%的现有“消费计算机”,在大多数情况下,它们忽略了返回值(因此我们可以讨论数十年,但从未有人会注意到!)

在这种情况下,在做出决定之前,请问以下问题: - 我是否有兴趣向我的调用方传达一些关于我的存在的信息? (如果我总是返回 0 ...就没有关于全部内容的线索) - 我的调用方是否有关于此通信的约定? (请注意,单个值不是一种约定:这不允许任何信息表示)

如果这两个答案都是否定的,则最好的解决方法可能是根本不编写主返回语句。(并让编译器根据它所工作的目标来决定)。

如果没有约定规定,0=成功可以满足大多数情况(使用符号可能存在问题,如果它们引入了一种约定)。
如果已有约定,请确保使用与其相一致的符号常量(并确保平台间的约定一致性,而不是值的一致性)。

4
一旦你开始编写可以返回各种退出状态的代码,你就开始定义所有这些状态。在这种情况下,EXIT_SUCCESS 在不是“魔术数字”的情况下很有意义。这使得你的代码更易读,因为每个其他的退出代码都将是 EXIT_SOMETHING。如果你只是编写一个在完成后返回的程序,return 0 是有效的,而且可能更清晰,因为它表明没有复杂的返回代码结构。

0

程序返回的内容只是一种约定。

不,我想不出任何情况下 "EXIT_SUCCESS" 不等于 "0"。

个人而言,我建议使用 "0"。

在我看来...


2
我已经编程C++十年了,但仍然记不住0在返回值方面是表示成功还是失败。 - lahjaton_j
2
@lahjaton_j 我明白。我认为这是因为它很反直觉:0代表假,而许多函数在失败/什么都不做时返回0 - meaning-matters
非常正确。因此有一个古老的笑话(因为0是假),关于main()函数的目的是运行你的程序并告诉你它是否“失败”了。 - Ray Toal
我记得是这样的:成功只需要一个信号,而失败可能需要多个信号。你如何将这个映射到整数上,以表示一个特殊含义的成功代码,并且能够轻松地测试它(使用简单的C代码和简单的机器代码)?通过将0定义为成功代码。 - undefined

-2

简洁版:可以不返回任何东西。

ok(Bjarne Stroustrup 这样说过……)在 main() 函数中不显式返回任何东西是可以的。如果您的操作系统需要返回值,编译器会处理这些事情。

这并不是要削弱 @KeithThompson@EmilioGaravaglia 在答案中讨论不同可能的返回值和如何了解程序的返回值被解释等情况的讨论。


-4

5
我非常怀疑这会使你的代码更加可移植或不可移植。 - Benjamin Lindley
11
不会,这个标准保证了0和EXIT_SUCCESS都表示成功终止。 - Keith Thompson
2
如果你说过:“如果使用EXIT_FAILURE,你的代码将更具可移植性”,那就是正确的。 - lopho

-5

有些编译器可能会出现问题-在Mac C++编译器中,EXIT_SUCCESS对我来说工作得很好,但在Linux C++编译器中,我必须添加cstdlib才能知道EXIT_SUCCESS是什么。除此之外,它们是相同的。


我指的是在Mac上,EXIT_SUCCESS可以正常工作,而无需包含cstdlib。 - Ambidextrous
8
如果 EXIT_SUCCESS 能够正常工作但没有包含 <stdlib.h> 或者 <cstdlib> 中的任何一个,那么一些其他的头文件必须已经直接或间接地定义过它。在 C++ 中,标准头文件会经常地使用#include来包含其它标准头文件。如果以下代码能够正常编译:int main() { return EXIT_SUCCESS; },则你的编译器可能有漏洞。 - Keith Thompson

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