ChatGPT解决这个技术问题 Extra ChatGPT

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

这是一个简单的问题,但我一直看到相互矛盾的答案: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 是什么,并且对宏做出假设可能会导致返回错误,因为宏可能会有所不同

K
Keith Thompson

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 将具有非零偶数值。)


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 语句上加上括号。就我个人而言,我认为它们使它看起来太像函数调用了。)
A
Alok Save

不要紧。两者都是一样的。

C++ 标准行情:

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


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

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

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

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

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


我认为您对人们期望 0 自动为坏的评论是不合时宜的。很多 API 使用 0 表示成功,而非 0 表示失败,即使在标准库中也是如此。例如 stdlib (fclose(), setvbuf(), ...), POSIX (listen(), pthread_create(), pipe(), ...), and many, many< /b> 其他库(例如 OpenGL [glGetError()]、zlib [deflate()/inflate()/...]、SDL [SDL_CreateWindowAndRenderer()/...] 等)。
当然,还有其他情况下 0 用于表示“成功”,但他说得对,这令人困惑。
d
danglingpointer

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

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

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

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

但是 - 不幸的是 - 这些概念在部署 C 语言时并不那么清楚(主要是为了编写 UNIX 内核),以及写成“返回 0 表示成功”的书籍的千兆克,因为这在操作系统上是正确的那个时候有一个 C 编译器。

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

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

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

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

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


P
Phonon

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


p
paulsm4

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

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

就个人而言,我推荐“0”。

恕我直言...


我已经编写 C++ 10 年了,但仍然不记得在返回值方面 0 表示成功还是失败。
@lahjaton_j 我明白了。它认为这是因为它违反直觉:0 为假,许多函数在失败/什么都不做时返回 0
e
einpoklum

tl;博士:你不能返回任何东西。

ok(Bjarne Stroustrup 这么说...)不明确地从 main() 函数返回任何内容。如果您的操作系统需要返回值,编译器会小心处理。

这并不是要偏离 @KeithThompson@EmilioGaravaglia 的答案中关于不同可能返回值的情况的讨论,以及了解如何解释程序的返回值等。


M
Mohammad Moghimi

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

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


我非常怀疑它是否会使您的代码或多或少具有可移植性。
不,不会的。该标准保证 0 和 EXIT_SUCCESS 都表示成功终止。
如果您说过“如果您使用 use EXIT_FAILURE,您的代码将更具可移植性”,那将是正确的。
A
Ambidextrous

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


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