简体   繁体   English

打印到stderr时检查fprintf时出错

[英]Error checking fprintf when printing to stderr

According to the docs, fprintf can fail and will return a negative number on failure. 根据文档,fprintf可能会失败,并会在失败时返回负数。 There are clearly many situations where it would be useful to check this value. 显然有很多情况下检查这个值是有用的。

However, I usually use fprintf to print error messages to stderr. 但是,我通常使用fprintf将错误消息打印到stderr。 My code will usually look something like this: 我的代码通常看起来像这样:

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

In these cases, is it still possible for fprintf to fail? 在这些情况下,fprintf仍然可能失败吗? If so, is there anything that can be done to display the error message somehow or is there is a more reliable alternative to fprintf? 如果是这样,有什么方法可以用来以某种方式显示错误消息,或者是否有更可靠的替代fprintf?

If not, is there any need to check fprintf when it is used in this way? 如果没有,是否需要检查fprintf以何种方式使用?

The C standard says that the file streams stdin, stdout, and stderr shall be connected somewhere, but they don't specify where, of course. C标准说文件流stdin,stdout和stderr应该在某处连接,但它们当然没有指定位置。 It is perfectly feasible to run a program with them redirected: 运行重定向的程序是完全可行的:

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

Your writes will succeed - but the information won't go anywhere. 你的写作会成功 - 但信息不会随处可见。 A more brutal way of running your program is: 运行程序的更残酷的方法是:

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

This time, it has been run without open file streams for stdout and stderr - in contravention of the the standard. 这一次,它运行时没有stdout和stderr的打开文件流 - 违反了标准。 It is still reading from /dev/null in the example, which means it doesn't get any useful data input from stdin. 它仍然是从示例中的/ dev / null读取,这意味着它没有从stdin获得任何有用的数据输入。

Many a program doesn't bother to check that the standard I/O channels are open. 许多程序都不愿意检查标准I / O通道是否打开。 Many a program doesn't bother to check that the error message was successfully written. 许多程序都不愿意检查错误消息是否已成功写入。 Devising a suitable fallback as outline by Tim Post and whitey04 isn't always worth the effort. 设计Tim Postwhitey04作为大纲的合适后备并不总是值得的。 If you run the ls command with its outputs suppressed, it will simply do what it can and exits with a non-zero status: 如果运行ls命令并禁止其输出,它将只执行它所能做的并以非零状态退出:

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

(Tested RHEL Linux.) There really isn't a need for it to do more. (经过测试的RHEL Linux。)确实没有必要做更多。 On the other hand, if your program is supposed to run in the background and write to a log file, it probably won't write much to stderr, unless it fails to open the log file (or spots an error on the log file). 另一方面,如果你的程序应该在后台运行并写入日志文件,它可能不会写很多东西到stderr,除非它无法打开日志文件(或在日志文件上发现错误) 。

Note that if you fall back on syslog(3) (or POSIX ), you have no way of knowing whether your calls were 'successful' or not; 请注意,如果您回到syslog(3) (或POSIX ),您无法知道您的通话是否“成功”; the syslog functions all return no status information. syslog函数都不返回任何状态信息。 You just have to assume that they were successful. 你只需要假设它们是成功的。 It is your last resort, therefore. 因此,这是你最后的选择。

Typically, you'd employ some kind of logging system that could (try) to handle this for you, or you'll need to duplicate that logic in every area of your code that prints to standard error and exits. 通常情况下,您可以使用某种日志系统来(尝试)为您处理此问题,或者您需要在代码的每个区域复制该逻辑,以打印到标准错误并退出。

You have some options: 你有一些选择:

  • If fprintf fails, try syslog. 如果fprintf失败,请尝试syslog。
  • If both fail, try creating a 'crash.{pid}.log' file that contains information that you'd want in a bug report. 如果两者都失败,请尝试创建一个'crash。{pid} .log'文件,其中包含您在错误报告中需要的信息。 Check for the existence of these files when you start up, as they can tell your program that it crashed previously. 启动时检查这些文件是否存在,因为它们可以告诉程序先前它已崩溃。
  • Let net connected users check a configuration option that allows your program to submit an error report. 让网络连接用户检查允许程序提交错误报告的配置选项。

Incidentally, open() read() and write() are good friends to have when the fprintf family of functions aren't working. 顺便说一下,当fprintf系列函数不工作时, open() read()write()是好朋友。

As whitey04 says , sometimes you just have to give up and do your best to not melt down with fireworks going off. 正如whitey04所说 ,有时你只需要放弃并尽力不让烟花消失。 But do try to isolate that kind of logic into a small library. 但是,请尝试将这种逻辑隔离到一个小型库中。

For instance: 例如:

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

Is much cleaner than a series of if else else if every place things could possibly go wrong. 比了一系列更清洁的if else else if每一个地方的东西可能出问题。

You could put the error on stdout or somewhere else... At some point you just have to give error reporting a best effort and then give up. 你可以将错误放在stdout或其他地方......在某些时候你只需要给出错误报告,然后放弃。

The key is that your app "gracefully" handles it (eg the OS doesn't have to kill it for being bad and it tells you why it exited [if it can]). 关键是你的应用程序“优雅地”处理它(例如,操作系统不必因为坏而杀死它,它会告诉你为什么退出它[如果它可以])。

Yes, of course fprintf to stderr can fail. 是的,当然fprintfstderr可能会失败。 For instance stderr could be an ordinary file and the disk could run out of space, or it could be a pipe that gets closed by the reader, etc. 例如, stderr可能是普通文件,磁盘可能空间不足,或者它可能是读取器关闭的管道等。

Whether you should check an operation for failure depends largely on whether you could achieve better program behavior by checking. 是否应该检查操作是否失败在很大程度上取决于您是否可以通过检查来实现更好的程序行为。 In your case, the only conceivable things you could do on failure to print the error message are try to print another one (which will almost surely also fail) or exit the program (which is probably worse than failing to report an error, but perhaps not always). 在你的情况下,你可以做的唯一可以想象的事情是打印错误信息失败是尝试打印另一个(几乎肯定也会失败)或退出程序(这可能比没有报告错误更糟糕,但也许不总是)。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM