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

Posted

技术标签:

【中文标题】我应该从 main() 返回 EXIT_SUCCESS 还是 0?【英文标题】:Should I return EXIT_SUCCESS or 0 from main()? 【发布时间】:2019-10-01 10:59:00 【问题描述】:

这是一个简单的问题,但我一直看到相互矛盾的答案:C++ 程序的主例程应该返回0 还是EXIT_SUCCESS

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

int main()return 0;

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

我认为EXIT_SUCCESS 会是更好的选择,因为其他软件可能希望将零视为失败,但我还听说如果您返回0,编译器无论如何都能够将其更改为不同的值。

【问题讨论】:

This answer about C90 解释了标准——0EXIT_SUCCESS 都被解释为成功。 我会在这里回复,因为我觉得将来会有其他人阅读此内容。基本上有很多关于“正确 C”的范式。一些范例更喜欢使用字面量而不是宏,例如,不是将 NULL 作为参数传递,它们可能会传递 (const char *)0 来指示它不仅仅是一个空值,但如果它不是空值,它应该是一个常量字符指针。其他范例更喜欢与类型无关,并且通过使用宏类型,它们可以避免在事情发生根本变化时更改其代码库。例如,许多 - @Dmitry Windows API 类型定义在较新的平台上是不正确的,但由于它们是宏,它们可以通过重新定义宏轻松地将所有类型更改为可以工作的类型,并且这些类型中的大部分只是根据定义进行缩放(例如 int 在不同的平台上是不同的)。总而言之,如果返回代码很重要并且将来可能会更改,请使用 EXIT_SUCCESS 之类的东西,否则返回 0 可能看起来像一个神奇的数字,但这仍然是完全有效的标准约定。错误代码主要用于程序将数字结果从一个管道传递到另一个,- @Dmitry 使用错误代码来调试你的程序有点弱,因为如果它确实返回 0,它是非常无用的信息,除非在某些情况下,程序中存在未引发的未处理错误,可能会导致程序静默中断,您需要检查它是否正常返回(0)或发生静默错误。数字返回对于根据输入将 0..255 从一个程序传递到另一个程序更有用,否则没有理由考虑它:要么返回 0,要么使用预编译的 main 内联 void “init” 调用而不是视觉上用无用的回报惹恼你。 @Dmitry 还值得注意的是,通过返回 EXIT_SUCCESS,您大大降低了检查程序返回的难度,因为如果人们查看您的主源代码并看到它返回一个宏,他们就不能自信说它是 0 而不去 EXIT_SUCCESS 的定义并检查它:在某些编辑器中很容易,在其他编辑器中很难。在您的文档中说它返回 EXIT_SUCCESS 是完全没用的,因为除非他们做出假设,否则人们不知道 EXIT_SUCCESS 是什么,并且对宏做出假设可能会导致返回错误,因为宏可能会有所不同 【参考方案1】:

你从一个程序返回的只是一个约定。

不,我想不出“EXIT_SUCCESS”不会为“0”的任何情况。

我个人推荐“0”。

恕我直言...

【讨论】:

我已经用 C++ 编程 10 年了,仍然不记得在返回值方面 0 是代表成功还是失败。 @lahjaton_j 我明白了。它认为这是因为它违反直觉:0 是错误的,许多函数在失败/什么都不做时返回 0【参考方案2】:

如果您使用 EXIT_SUCCESS,您的代码将更具可移植性。

http://www.dreamincode.net/forums/topic/57495-return-0-vs-return-exit-success/

【讨论】:

我非常怀疑它是否会使您的代码更便携或更不便携。 不,不会。该标准保证 0 和 EXIT_SUCCESS 都表示成功终止。 如果你说“如果你使用 use EXIT_FAILURE,你的代码会更便携”,那就对了。【参考方案3】:

没关系。两者都是一样的。

C++ 标准引用:

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

【讨论】:

这对编译器来说无关紧要,但作为风格问题可能很重要。 @celtschk:风格问题是基于感知的,也就是非标准化,因此这不算作差异。您只能将苹果与苹果进行比较,而不能将苹果与梨进行比较。 不保证EXIT_SUCCESS == 0。另一方面,没有充分的理由不这样做。 @PravasiMeet:一个系统可能有多个值表示成功。 功能重于形式,但清晰重于功能。我可以从专业经验告诉你,风格在编程中非常重要。【参考方案4】:

一些编译器可能会产生问题 - 在 Mac C++ 编译器上,EXIT_SUCCESS 对我来说工作得很好,但在 Linux C++ 编译器上,我必须添加 cstdlib 才能知道 EXIT_SUCCESS 是什么。除此之外,它们是一回事。

【讨论】:

我的意思是在 Mac 上 EXIT_SUCCESS 在不包含 cstdlib 的情况下工作。 如果EXIT_SUCCESS 在不包含&lt;stdlib.h&gt;&lt;cstdlib&gt; 的情况下工作,则必须有其他标头直接或间接定义了它。在 C++ 中,标准头文件到 #include 其他标准头文件是很常见的。如果编译没有错误:int main() return EXIT_SUCCESS; 那么你的编译器可能有问题。【参考方案5】:

根据定义,0 是一个幻数。 EXIT_SUCCESS 几乎普遍等于 0,很高兴。那么为什么不直接返回/退出 0 呢?

退出(EXIT_SUCCESS);含义非常明确。

退出(0);另一方面,在某些方面是违反直觉的。不熟悉 shell 行为的人可能会认为 0 == false == 不好,就像 C 中 0 的所有其他用法一样。但不是 - 在这种特殊情况下,0 == 成功 == 好。对于大多数有经验的开发人员来说,这不会是一个问题。但是,为什么要无缘无故地绊倒新人呢?

tl;dr - 如果为您的幻数定义了一个常量,那么几乎没有理由不首先使用该常量。它更易于搜索,通常更清晰等,而且不会花费您任何费用。

【讨论】:

我认为您的 cmets 关于人们期望 0 自动变坏的说法是错误的。很多 API 使用 0 表示成功,使用非 0 表示失败,即使在 stdlib 中也是如此。例如。 stdlib (fclose(), setvbuf(), ...), POSIX (listen(), pthread_create(), pipe(), ...) 和许多,许多 其他库(例如 OpenGL [glGetError()]、zlib [deflate()/inflate()/...]、SDL [SDL_CreateWindowAndRenderer()/...] 等)。 当然,还有其他情况下 0 用于表示“成功”,但他说得对,这让人困惑。【参考方案6】:

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

如果您要在程序失败时使用EXIT_FAILURE,那么您不妨在程序成功时使用EXIT_SUCCESS,只是为了对称。

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

使用0 有一个次要优势,即您在C 中不需要#include &lt;stdlib.h&gt;,或者在C++ 中不需要#include &lt;cstdlib&gt;(如果您使用return 语句而不是调用exit())——但是对于任何重要规模的程序,无论如何您都将直接或间接地包含 stdlib。

就此而言,在从 1999 年标准开始的 C 以及所有版本的 C++ 中,到达main() 的末尾无论如何都会隐含return 0;,因此您可能不需要使用0 或@ 987654338@ 明确。 (但至少在 C 语言中,我认为明确的 return 0; 是更好的风格。)

(有人问及OpenVMS。我很久没用了,但我记得奇数状态值通常表示成功,偶数值表示失败。C 实现将0 映射到1,因此return 0; 表示终止成功。其他值不变传递,因此return 1; 也表示终止成功。EXIT_FAILURE 将有一个非零偶数值。)

【讨论】:

exit(0) 映射到退出状态 1 时,怎么可能为 OpenVMS 实现 POSIX 实用程序? (如果我正确理解你的最后一段) @Rhymoid:这是由 C 指定的,而不是 POSIX。 @DeanP: 0EXIT_SUCCESS 不能保证具有相同的值(我在回答中提到过),但它们都表示成功终止。 EXIT_SUCCESS 在风格上更好如果你也在使用EXIT_FAILURE,但exit(0) 没问题。 这是个人的(出于相同的动机:明确),但我喜欢“返回(0)”(或!= 0),因为 shell 脚本“$?”兼容性(大多数 unix 程序返回 "$?"=0 表示成功)。 @AndréA.G.Scotá:POSIX 保证 EXIT_SUCCESS==0。 (而且你不需要在 return 语句上加上括号。就我个人而言,我认为它们让它看起来太像函数调用了。)【参考方案7】:

一旦您开始编写可以返回无数退出状态的代码,您就可以开始#define'ing 所有这些状态。在这种情况下,EXIT_SUCCESS 在不是“magic number”的情况下是有意义的。这使您的代码更具可读性,因为其他所有退出代码都是EXIT_SOMETHING。如果您只是编写一个完成后将返回的程序,return 0 是有效的,并且可能更简洁,因为它表明没有复杂的返回代码结构。

【讨论】:

【参考方案8】:

这是一个永无止境的故事,反映了“互操作性和可移植性”的局限性(一个神话)。

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

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

现在,在多对多场景中(许多语言用于向许多系统编写程序),“成功”的语言约定与操作系统之间的对应关系(没有人可以授予始终是同样)应该由特定目标平台的库的特定实现来处理。

但是 - 不幸的是 - 这些概念在部署 C 语言(主要用于编写 UNIX 内核)时并没有那么清楚,并且写成“返回 0 表示成功”的书籍的 Gigagrams,因为那是真的当时的操作系统有一个 C 编译器。

从那时起,就再也没有关于如何处理此类通信的明确标准。 C 和 C++ 对“返回值”有自己的定义,但没有人授予正确的操作系统翻译(或者更好:没有编译器文档对此有任何说明)。 0 表示成功,如果对于 UNIX - LINUX 和 - 出于独立的原因 - 对于 Windows 也是如此,这涵盖了 90% 的现有“消费者计算机”,在大多数情况下 - 忽略返回值(所以我们可以讨论了几十年,但没人会注意到!)

在这种情况下,在做出决定之前,请询问以下问题: - 我是否有兴趣向来电者传达一些关于我现有的信息? (如果我总是返回 0 ......所有事情背后都没有线索) - 我的来电者是否有关于此通信的约定? (请注意,单个值不是约定:不允许任何信息表示)

如果这两个答案都不是,那么好的解决方案可能是根本不编写主要的 return 语句。 (并让编译器来决定,相对于目标是如何工作的)。

如果没有约定 0=成功满足大多数情况(如果符号引入约定,则使用符号可能会有问题)。

如果有约定,请确保使用与其一致的符号常量(并确保平台之间的约定一致,而不是价值一致)。

【讨论】:

以上是关于我应该从 main() 返回 EXIT_SUCCESS 还是 0?的主要内容,如果未能解决你的问题,请参考以下文章

如何从我的属性中获取两个值以返回到我的main方法?

如何从函数返回数据类型 int** 并存储它?

java中哪些内容应该放在main函数中?

main() 在 C 和 C++ 中应该返回啥?

main() 在 C 和 C++ 中应该返回啥?

从 main 返回零是不是必要,从 main 的返回值如何有用?