2011-01-31 119 views
8

根据文档,fprintf可能会失败,并会在失败时返回负数。显然很多情况下,检查这个值是有用的。打印到标准错误时检查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的使用方法?

回答

12

C标准规定文件流stdin,stdout和stderr应该连接到某个地方,但是它们当然不指定在哪里。与他们重定向运行一个程序是完全可行的:

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

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

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

这个时候,已经没有了输出和错误打开文件流运行 - 违反标准的。它在示例中仍然是从/ dev/null读取的,这意味着它不会从stdin获得任何有用的数据输入。

许多程序不会检查标准I/O通道是否打开。许多程序不会检查错误消息是否成功写入。根据Tim Postwhitey04的大纲设计合适的回退并不总是值得的。如果运行ls命令其输出的抑制,它只会尽其所能,并退出与非零状态:

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

(测试RHEL Linux操作系统。)实在没有必要为它多做。另一方面,如果您的程序应该在后台运行并写入日志文件,那么它可能不会写入太多的stderr,除非无法打开日志文件(或者在日志文件中出现错误) 。

请注意,如果您回退syslog(3)(或POSIX),则无法知道您的呼叫是否“成功”;系统日志功能全部不返回状态信息。你只需要假设他们是成功的。因此,这是你的最后手段。

+0

我想知道为什么这没有收到更多的票比我的答案。 +1。 – 2011-01-31 13:03:11

4

你可以把错误放在标准输出或其他地方......在某些时候,你只需要给错误报告一个尽力,然后放弃。

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

9

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

你有一些选择:

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

顺便说一句,open()read()write()是很好的朋友,当函数的fprintf中家庭工作不有。

由于whitey04 says,有时你只是不得不放弃,尽你所能不要放弃烟花爆竹。但是试图将这种逻辑分离成一个小型图书馆。

例如:

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

比一系列ifelseelse if每一个地方的东西可能出问题干净多了。

2

某些程序要记录的错误消息将建立一个备用堆栈在程序启动时保留的存储器中的某些量(见sigaltstack(2)可以由信号处理程序(通常SIGSEGV使用)到报告错误根据记录错误的重要性,你可以调查使用备用堆栈来预先分配一些内存块,但这可能不值得:)但有时你会给出任何提示提示发生了什么事。

3

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

是否应该检查某个操作是否失败主要取决于您是否可以通过检查获得更好的程序行为。在你的情况下,你可以做的唯一可以做的事情就是不打印错误消息,就是尝试打印另一个(这几乎肯定会失败)或者退出程序(这可能比报告错误更糟糕,但也许可能更糟糕不总是)。