打印到stderr时检查fprintf时出错

时间:2011-01-31 00:18:37

标签: c

根据文档,fprintf可能会失败,并会在失败时返回负数。显然有很多情况下检查这个值是有用的。

但是,我通常使用fprintf将错误消息打印到stderr。我的代码通常看起来像这样:

rc = foo();
if(rc) {
  fprintf(stderr, "An error occured\n");
  //Sometimes stuff will need to be cleaned up here
  return 1;
}

在这些情况下,fprintf仍有可能失败吗?如果是这样,有什么方法可以用来以某种方式显示错误消息,或者是否有更可靠的替代fprintf?

如果没有,是否需要在以这种方式使用时检查fprintf?

5 个答案:

答案 0 :(得分:12)

C标准说文件流stdin,stdout和stderr应该在某处连接,但它们当然没有指定位置。运行重定向的程序是完全可行的:

some_program_of_yours >/dev/null 2>&1 </dev/null

你的写作会成功 - 但信息不会随处可见。运行程序的一种更残酷的方式是:

some_program_of_yours >&- 2>&- </dev/null

这一次,它在没有stdout和stderr的打开文件流的情况下运行 - 违反了标准。它仍然是从示例中的/ dev / null读取,这意味着它没有从stdin获得任何有用的数据输入。

许多程序都不愿意检查标准I / O通道是否打开。许多程序都不愿意检查错误消息是否已成功写入。通过Tim Postwhitey04设计合适的后备并不总是值得的。如果运行ls命令并且其输出被抑制,它将尽其所能并以非零状态退出:

$ ls; echo $?
gls
0
$ ls >&- 2>&-; echo $?
2
$

(经过测试的RHEL Linux。)确实没有必要做更多。另一方面,如果你的程序应该在后台运行并写入日志文件,它可能不会写很多东西到stderr,除非它无法打开日志文件(或在日志文件上发现错误)

请注意,如果您回到syslog(3)(或POSIX),则无法知道您的通话是否“成功”; syslog函数都不返回任何状态信息。你只需要假设它们是成功的。因此,这是你的最后手段。

答案 1 :(得分:9)

通常情况下,您会使用某种日志系统(可以尝试)为您处理此问题,或者您需要在代码的每个区域复制该逻辑,以打印到标准错误并退出。

你有一些选择:

  • 如果fprintf失败,请尝试syslog。
  • 如果两者都失败,请尝试创建一个'crash。{pid} .log'文件,其中包含您在错误报告中需要的信息。启动时检查这些文件是否存在,因为它们可以告诉程序它之前崩溃了。
  • 让网络连接用户检查允许程序提交错误报告的配置选项。

顺便提一下,当fprintf系列功能不起作用时,open() read()write()是好朋友。

作为whitey04 says,有时你只需要放弃并尽力不让烟花消失。但是,请尝试将这种逻辑隔离到一个小型库中。

例如:

    best_effort_logger(LOG_CRIT, "Heap corruption likely, bailing out!");

比一系列if else else if更清晰,每个地方都可能出错。

答案 2 :(得分:4)

您可以将错误放在stdout或其他地方......在某些时候,您只需要尽力报错,然后放弃。

关键是你的应用程序“优雅地”处理它(例如,操作系统不必因为坏而杀死它,并告诉你为什么它会退出[如果可以])。

答案 3 :(得分:3)

是的,当然fprintfstderr可能会失败。例如,stderr可能是普通文件,磁盘可能空间不足,或者它可能是读取器关闭的管道等。

是否应该检查操作是否失败在很大程度上取决于您是否可以通过检查来实现更好的程序行为。在你的情况下,你可以做的唯一可以想象的事情是打印错误信息失败是尝试打印另一个(几乎肯定也会失败)或退出程序(这可能比没有报告错误更糟糕,但也许并非总是如此。

答案 4 :(得分:2)

真正想要记录错误消息的某些程序将在程序启动时设置备用堆栈以保留一定量的内存(请参阅sigaltstack(2)信号处理程序(通常是SIGSEGV)可以使用它来报告错误。根据记录错误的重要性,您可以调查使用备用堆栈预分配一些内存。可能不值得:)但有时你会为发生的事情提供一些提示