【问题标题】:Return Code on failure. Positive or negative?失败时返回代码。正面还是负面?
【发布时间】:2018-04-26 05:08:30
【问题描述】:

在 Linux 的特殊情况下,C 程序可能无法执行。 示例:您分配了一些空间,但操作系统拒绝了它。

char *buffer = (char *) malloc(1024);
if (buffer == NULL)
    return ENOMEM;

此故障由传递给操作系统的返回代码标记。

  • 返回码 0 (EXIT_SUCCESS) 被标记为成功执行。
  • 不为 0 的返回码被标记为失败。

所以我的问题是,当程序检测到错误时,约定是什么。 它应该返回一个正的还是负的返回码?

我的教授告诉我在 UNIX/Linux 中总是返回一个否定的错误代码。但是 errno-Codes 都是正整数。 EXIT_FAILURE 中的define-Statement 也是1,一个正整数。 所以我的代码应该是这样的:

char *buffer = (char *) malloc(1024);
if (buffer == NULL)
    return -ENOMEM;

或喜欢上面的代码?我从 Linux-Kernel-Modules 了解到,在大多数情况下,它们会在失败时返回负错误代码。

感谢您的帮助。

【问题讨论】:

  • 您混淆了errno 中的错误代码和您从main 返回的错误代码。这是两个不同的东西。如果您的程序因任何原因失败,请从main 返回EXIT_FAILURE,否则返回EXIT_SUCCESSthis 也可能很有趣

标签: c linux return errno


【解决方案1】:

所以我的问题是,当程序检测到 错误。它应该返回一个正的还是负的返回码?

您没有做出这种选择的奢侈(或责任)。一般来说,从 C 的角度来看,您的选择分为三类:

  • 您指定的退出状态是0EXIT_SUCCESS(不一定不同)。这表示成功完成。

  • 您指定的退出状态是EXIT_FAILURE。这表示未成功完成。

  • 您指定的退出状态是其他任何东西。

在每种情况下,向宿主环境发出信号的结果都是实现定义的,尽管在​​第一种情况下是成功的,而在第二种情况下是失败的。

现在,在 Linux 和其他实现 POSIX exit() 语义的操作系统上,实现定义已标准化:

status 的值可以是0EXIT_SUCCESSEXIT_FAILURE 或任何其他值,尽管只有最低有效 8 位(即status & 0377)可从@987654331 获得@和waitpid();

IEEE Std 1003.1-2008, 2016 Edition;添加了重点)。这些是传统的 UNIX 语义;只有您指定的退出状态中最不重要的 8 位重要,所以签名丢失。但是,当前版本的 POSIX 继续说:

完整的值应从waitid()siginfo_t 中提供给SIGCHLD 的信号处理程序。

因此,如果父进程知道要查找负数,您可以将负数传达给它。但是,一般情况下,它不会这样做。特别是,如果父进程是 shell,那么它就不会这样做。

我的教授告诉我在 UNIX/Linux 中总是返回一个否定的错误代码。

这听起来更像是关于函数返回码的说明main(),但我不明白为什么你认为我们对你教授的意思的第二次猜测会比直接请你的教授澄清。

但是 errno-Codes 都是正整数。

嗯,要与您的教授澄清的另一件事是,他是否向您提供了有关他希望您如何为他的班级编写函数的具体说明(更有可能),或者他是否对通用 C 或 POSIX 约定做出断言(不太可能,因为有许多不正确的 POSIX 函数),或其他什么。

请注意,C 标准库函数不返回 errno 代码。当他们返回一个指示失败的代码(通常但不总是一个负数)时,程序员必须查阅errno 变量以了解详细原因——函数返回代码通常不携带该信息。一些由 POSIX 标准化但不是 C do 标准化的函数直接返回 errno 代码;显然,这些不符合你教授的处方。

还请注意,errno 值用于在同一程序调用的函数之间进行通信,而不是用于与程序环境进行通信。它们不打算用作程序退出状态,特别是不能保证它们的值适合八位(见上文)。

EXIT_FAILURE 中的define-Statement 也是1,一个正整数。所以我的代码应该是这样的:

EXIT_FAILURE 的值取决于实现。因此,您只能从中收集特定于实现的见解。但是,如您所见,在您的实现中指示程序失败的通用退出状态是1

在 Linux 和其他 POSIX(-ish) 系统上,您可以通过选择 1 到 125 之间的故障状态来实现与 shell 的最佳集成,因为 shell 指定状态 126-255 的特殊意义,当然,解释状态 0成功。

char *buffer = (char *) malloc(1024);
if (buffer == NULL)
    return -ENOMEM;

或喜欢上面的代码?我从 Linux-Kernel-Modules 知道,在大多数情况下 如果失败,它们会返回一个否定的错误代码。

再次,不。 Errno 代码不打算用作程序退出代码,只有在相当特殊的情况下,您才应该尝试以否定状态退出。一个常见的约定是向stderr 写入一条信息性错误消息(perror() 正是用于此目的),然后以状态 1 或(更好,IMO)EXIT_FAILURE 退出。

如果您想提供描述故障性质的退出代码,那么您可以根据每个程序定义它们的值和重要性,请记住,为了获得最佳兼容性,您只能使用 1 - 125 .

【讨论】:

  • (顺便说一句,一个很好的答案)。对125 感到好奇吗?看起来如此非二进制。关于为什么“shell 指定状态 126-255 的特殊意义”而不是“128-255”的任何想法 - 或者它就是这样?
  • @chux,对于由信号终止的命令,shell 会报告大于 128 的退出状态。然后它将剩余的失败代码中的前几个用于预定义目的:当未找到请求的命令时报告 127,当找到请求的命令但无法执行时报告 126。这记录在the shell language specification 的第 2.8.2 节中。当然,程序不必与之合作,这就是为什么我将这样做称为兼容性考虑。
【解决方案2】:

程序中未进一步指定的错误代码的约定是使用EXIT_FAILURE。它将被定义为您的操作系统识别为失败退出代码的值。

errno.h 中定义的宏不作为进程的返回码,而仅作为程序执行期间的错误。标准库会将它们放在全局 errno 中,如果您愿意,也可以将它们用作函数的返回码。其中三个由 C 标准指定:EDOMEILSEQERANGE。 POSIX 指定了更多内容。不要将这些用作来自main() 的返回码(或作为exit() 的参数)。

【讨论】:

    【解决方案3】:

    进程在 UNIX/Linux 上的退出代码、main() 中的 return 语句或对 exit() 的调用在范围内无符号 0 - 255。

    从一个函数,它可以是你想要的任何类型。许多库函数在出错时返回 -1

    但这并不总是可行的,尤其是通常返回指针的函数。按照惯例,这些函数在出错时返回NULL,例如fopen()malloc()

    这些返回代码仅表示发生了错误,而不是错误是什么,通常(发生错误时)全局errno 也设置为正错误代码以提供更多信息。见man errno

    【讨论】:

      【解决方案4】:

      通常,Linux 程序在成功时返回 0,在失败时返回非零。有一些例外(例如 grep,它具有表示是否找到匹配项的值)。这样做的原因是 bash 提示符将 true 定义为 0,将 false 定义为 1,因此它使脚本编写变得简单:

      somecmd && action "if succesful"
      

      但这就是程序本身。对于程序内部的代码,通常有多种约定。一种常见的方法是在成功时返回 0(或正数),或在失败时返回负数。这背后的原因是所有指令集(我知道)都有一个分支如果为零或分支如果小于零指令,这意味着它只有一个指令来进行比较(如反对必须进行比较,然后在比较匹配时进行分支)。

      【讨论】:

      • 真正的“原因”是因为失败的方式有多种,而成功的方式通常只有一种。
      • 实际上,“真正的原因”是原始程序员决定做的事情。可能有多种成功方式和多种失败方式——在这些情况下,使用正数和负数是确定失败的一种方便有效的方法。
      • 我只是更正了“C 这样做是因为 bash 这样做”位。其余的请随意编辑您自己的答案:-)
      【解决方案5】:

      errno 是一个全局变量,您可以使用错误号设置。约定是设置errno,然后返回一个负数(通常是负数)。负返回值表示应检查errno。使用您的示例(并将其放入函数中),它可能如下所示:

      int allocate_buffer(char *buffer) {
          buffer = malloc(1024);
          if (buffer == NULL) {
              errno = ENOMEM;
              return -1;
          }
          return 0;
      }
      

      然后调用者将根据返回值知道是否有错误,并检查 errno 以查看错误是什么并决定如何从那里继续。

      【讨论】:

        【解决方案6】:

        5.1.2.2.3 程序终止

        如果主函数的返回类型是与int兼容的类型, 从初始调用返回到主函数相当于 使用 main 返回的值调用 exit 函数 函数作为它的参数; 11) 到达终止 main函数返回值为0。如果返回类型不是 兼容int,终止状态返回给主机 环境未指定。

        7.22.4.4 退出函数:

        最后,控制权返回到宿主环境。如果值 状态为零或 EXIT_SUCCESS,实现定义的形式 返回状态成功终止。如果 status 的值为 EXIT_FAILURE,实现定义的状态形式 返回不成功的终止。否则状态 返回的是实现定义的。

        我发现这是自我描述的。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-06-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多