【问题标题】:Error checking fprintf when printing to stderr打印到 stderr 时检查 fprintf 时出错
【发布时间】:2011-06-18 07:24:34
【问题描述】:

根据文档,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是否需要检查?

【问题讨论】:

    标签: c


    【解决方案1】:

    C 标准规定文件流stdinstdoutstderr 应连接到某个地方,但它们当然没有指定位置。 (C11§7.21.3 Files ¶7:

    在程序启动时,三个文本流是预定义的,不需要显式打开——标准输入(用于读取常规输入)、标准输出(用于写入常规输出)和标准错误(用于写入诊断输出)。最初打开时,标准错误流没有完全缓冲;当且仅当可以确定流不引用交互式设备时,标准输入和标准输出流才会被完全缓冲。

    使用重定向的标准流运行程序是完全可行的:

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

    您的写入会成功 - 但信息不会去任何地方。运行程序的更残酷的方式是:

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

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

    许多程序都懒得检查标准 I/O 通道是否打开。许多程序不会费心检查错误消息是否已成功写入。为Tim Postwhitey04 设计一个合适的后备方案并不总是值得付出努力。如果您在其输出被抑制的情况下运行ls 命令,它只会做它可以做的事情并以非零状态退出:

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

    (经过测试的 RHEL Linux。)确实不需要它做更多的事情。另一方面,如果您的程序应该在后台运行并写入日志文件,它可能不会向stderr 写入太多内容,除非它无法打开日志文件(或在日志中发现错误)文件)。

    请注意,如果您使用syslog(3)(或POSIX),您将无法知道您的呼叫是否“成功”; syslog 函数均不返回任何状态信息。你只需要假设他们是成功的。因此,这是您最后的选择。

    【讨论】:

    • 我想知道为什么这没有得到比我的回答更多的选票。 +1。
    • @Tim:谢谢,但您的回答也提供了很好的信息——而且您首先到达那里。而你的关键点——使用一个做错误报告的函数,而不是每次你需要报告错误的一段代码——非常重要。
    【解决方案2】:

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

    你有一些选择:

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

    顺便说一句,open() read()write() 是 fprintf 系列函数不工作时的好朋友。

    作为whitey04 says,有时你只需要放弃并尽力不因烟花爆竹而崩溃。但请尝试将这种逻辑隔离到一个小型库中。

    例如:

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

    ifelseelse if每一个可能出错的地方都要干净。

    【讨论】:

      【解决方案3】:

      您可以将错误放在标准输出或其他地方...在某些时候您只需要尽最大努力报告错误然后放弃。

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

      【讨论】:

        【解决方案4】:

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

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

        【讨论】:

          【解决方案5】:

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2018-07-18
            • 2017-01-20
            • 2015-12-07
            • 2021-05-23
            • 1970-01-01
            • 2011-03-29
            • 2011-07-25
            • 1970-01-01
            相关资源
            最近更新 更多