【问题标题】:Is checking the return value of printf important?检查 printf 的返回值重要吗?
【发布时间】:2017-08-13 06:29:21
【问题描述】:

在我的一个大学项目中,我得到了扣分和教授的反馈,说我没有处理 printf 错误。

英文 --> / * ### FB: Error handling printf () is missing * /

/* ### FB: Fehlerbehandlung printf() fehlt */
    printf("%7lu %8lld %10s %3lu %-8s %-8s %8lu %12s  %s %s %s\n",
           sb->st_ino, nblks, permstr, (unsigned long) sb->st_nlink,
           username, groupname, sb->st_size,
           ntime, filename, (symlink ? "->" : ""),
           (symlink ? symlink : "")
           );

我的问题是,总是检查printf 函数的返回值并处理错误真的很重要吗?即使我发现错误,我仍然会使用fprintf 打印到stderr,为此我必须再次检查fprintf 的返回类型。

那么应该什么时候检查返回值,应该如何处理呢?

【问题讨论】:

  • 第一个答案可能有用stackoverflow.com/questions/13535557/…
  • 总是检查scanf,但我承认从不检查printf
  • @SeekAddo:我猜你的教授可能没有任何专业编写 C 的经验,所以他对错误检查的看法可能只是理论/迂腐。
  • @SeekAddo,正如我所说,这取决于您将如何处理此类错误。更有可能的是,如果您处于完全需要检查的情况,那么处理将包括终止发生错误的线程或进程。就个人而言,我会在此之前向stderr 发送消息,但that 是绝对没有意义检查返回值(fprintf()/fputs())的情况。跨度>
  • 我不同意这是基于意见的。很明显,检查 printf 的结果并没有给你任何有意义的行动。唯一基于意见的是您是否应该坚持检查它,以保持一致的编码风格或避免警告。但这不是这里的问题。投票重新开放。

标签: c return output printf


【解决方案1】:

一般来说,您应该始终检查函数的返回值是否有错误。

然而,在printf 的情况下,在大多数情况下这样做几乎没有用处。正如您所提到的,如果它确实失败了,您可以使用fprintf 打印到stderr,但这会引发 是否应该检查错误的问题。

如果您不重定向或重新打开stderr,您可能会遇到同样的问题,在这种情况下,这可能无关紧要,但如果stderr 指向其他地方,那么写在那里可能有价值。您也可以退出该过程,但您需要确定这样做是否有意义。

您可能要检查返回值的一个值得注意的时间是,如果您要跟踪为格式化目的打印了多少字符。我在写入日志文件以确定何时滚动日志时使用fprintf 完成了此操作,但由于printf 通常写入交互式控制台(如果不是由于重定向,您不会知道) ,这实际上并不适用。

至于你的教授,我唯一的猜测是他希望你养成检查错误的习惯。这是一件好事,但是像大多数规则一样,也有例外,这就是其中之一。

【讨论】:

  • 如果printf() 失败了怎么办?您可以中止线程或进程,在某些情况下这样做可能有意义。还有其他可能性。此外,如果您选择发出错误消息,这不一定是一个坏主意,那么合适的流是stderr,并且没有理由假设仅仅因为printf()(到stdout)失败,@ 987654332@将无效。
  • @TripeHound,相反,如果适用的指令要求识别和处理所有错误,那么我认为没有理由排除printf()产生的错误。此外,我认为严格执行这种约束有一些迂腐的价值,不是因为特别是细节printf,而是因为理解如何详细符合规范的一般重要性。也有点促进人们认识到计算机不会做出那种建议对printf()破例的价值判断。
  • @JohnBollinger printf 系列函数具有可怕的错误检查,是可憎的变量参数列表,这一事实使得这个讨论毫无意义。这就像争论为什么有人在将大象带入您的瓷器店之前没有清洁它们的脚。 printf 代码使用不正确的格式说明符或错误的参数等将在许多形式的 UB 中剧烈爆炸。它不会优雅地返回。另外,它不一定保证是可重入的。正确的解决方案是完全避免stdio.h,而不是试图打磨废话。
  • @Lundin 一个体面的编译器会在编译时检查可变参数是否已知格式字符串(什么时候不知道?),因此如果您使用 -Wall 编译,则永远不会发生这种 UB -错误
  • @k_g 所有主流操作系统都是用 C 编写的,它们的 API:s 也是如此。当然,用 C 或 C++ 破解 GUI 是有些痛苦的。如果需要,您可以将 Java 或 C# 用于 GUI,将 C 用于后端。
【解决方案2】:

为清楚起见 - printf() 返回 ...

printf 函数返回传输的字符数,如果发生输出或编码错误,则返回负值。 C11 §7.21.6.3 3


检查printf() 的返回值是否为负值是pedantic,通常不需要。可以考虑以下情况:


环境限制

带有"%s" 的单个printf() 可能会超出环境限制并导致printf() 返回负值。这并不意味着fprintf(stderr, ... 上的后续消息也必须失败。

任何一次转换可以产生的字符数至少应为 4095。C11 §7.21.6.1 15


弱输出设备

已知stdout 经常通过需要检测输出故障的通信接口重定向的情况。尽管屏幕输出取得了非凡的成功,但其他各种输出流(如串行(rs232))并非如此。在这种情况下,stdoutstderr 可能重定向不同,因此 stderr 可能保持可靠。


在任何情况下,如果教授在曲线上评分,很可能很多人都会产生相同的减分 - 所以没有成绩差异。适应有奇怪要求和期望的客户。

【讨论】:

  • 大多数情况下,当 stdout 是串行端口时,您会在断开连接时收到 SIGHUP。为了将其转换为 printf 的 EIO 错误,您需要明确忽略 SIGHUP;默认操作是终止进程,并且在适合其他操作的应用程序中,安装信号处理程序是正常的。类似的观察结果适用于 SIGPIPE,这是另一个可能的 stdout 失败原因。
  • +(int)(M_PI/3) 最后一句。钉在棺材上。
  • FWIW,我尝试使用 gcc 打印一对带有 int n = printf("%s %s\n", buf, buf); 的 2,000,000,000 个字符串(+ \0),结果是预期的文本和 -294,967,2944,000,000,002 - (UINT_MAX + 1)) 的负返回值- 所以该平台上的错误指示器并不多。
【解决方案3】:

不检查返回值被认为是不好的做法。但是,如果您通过在函数调用前添加(void) 明确声明忽略返回值,则它被认为是干净的:

(void) printf(...);

这表明,你知道有返回值,但你故意忽略它。

【讨论】:

  • 没有。将返回值转换为 void 表示您有意忽略它是一种抑制诊断的机制。它是丑陋的,冗长的,并且可能令人困惑。它也绝对un干净,因为它隐藏了问题而不是修复它。
  • @JohnBollinger 与 not 转换结果相比,这意味着“我忘记了这个函数返回任何东西,因此我的代码中可能存在错误”。那个清洁剂到底有多干净?显式转换意味着“我知道这个函数会返回一些东西,但我不在乎”。在 printf 的情况下,它可能不会返回任何有意义的东西。如果它不是那么可怕的函数,它会在不正确的格式字符串等情况下返回错误,但我从未见过真正这样做的实现。
  • @Lundin,如果您一开始就足够注意这个问题并考虑转换为void,那么简单地评论关于您故意忽略返回值。这还让你有机会说出你为什么忽略它。
  • @JohnBollinger A (void) 通知编译结果被忽略。注释不会这样做,即使它对程序员来说是更清晰和有用的信息。一些编译器提供有关未使用的返回值的通知。 (void) 使该通知实例静音。
  • @JohnBollinger 有趣的编码模型。如果确定忽略返回值是一个合理的选择,那么构建器是否使用(void) 编辑代码,忽略选择诊断(可能是 100 到 1000 个),全面关闭警告,然后返回给编写者编辑(void) 还是什么?我的模型是通过代码审查的代码不再生成诊断的模型。如果需要这样的迂腐诊断,那么将存在许多 (void),并且诊断不会在下一次构建时不断弹出。
【解决方案4】:

Unix 的理念是stdout(尽管不一定是stderr)应该是可进一步处理的。编译器和生成器将其用于代码输出。 stdout 应该是您的流程产品所在的位置。如果该产品被缩短,您的流程不应返回EXIT_SUCCESS。 我说一定要检查那些写到stdout

(另一方面,stderr 或多或少是为了方便。如果你正在使用它,你可能已经处于错误状态,如果你的错误报告失败,那么你就没有多少了可以(尽管您仍然应该使用返回码表示错误)。)

【讨论】:

  • @Dmitri 在这种情况下,如果作者捕捉到任何信号,printf 可能会从EINTRs 失败。否则,它不应该失败,AFAIK(前提是操作系统和阅读器都可以)。如果您使用常规文件作为中介(> rediction)进行 IPC,则可能会出现 IO 错误。
【解决方案5】:

没有。在现实世界中,相对于文化中的学术练习mit einem Ruf für Pedanterie,检查printf()close() 或其他很多的返回值并不重要事物。如果没有合理的方法来处理一条信息,为什么还要收集它呢?

【讨论】:

【解决方案6】:

如果您正在编写一个输出 JSON 的应用程序(例如:从 DB 中读取,将数据导出到 stdout),则程序的调用者可能会将输出重定向到一个文件中。在这种情况下 - 磁盘可能会被填满。

问题: 谁会抱怨磁盘已满:shell 还是您的程序?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-07-03
    • 1970-01-01
    • 1970-01-01
    • 2016-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多