C语言 打印到 stderr 时检查 fprintf 时出错
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4846562/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Error checking fprintf when printing to stderr
提问by Rupert Madden-Abbott
According to the docs, fprintf can fail and will return a negative number on failure. There are clearly many situations where it would be useful to check this value.
根据文档, fprintf 可能会失败,并且会在失败时返回负数。很明显,在许多情况下检查这个值是有用的。
However, I usually use fprintf to print error messages to stderr. My code will usually look something like this:
但是,我通常使用 fprintf 将错误消息打印到 stderr。我的代码通常如下所示:
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? 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 仍然有可能失败吗?如果是这样,是否可以采取任何措施以某种方式显示错误消息,或者是否有更可靠的 fprintf 替代方案?
If not, is there any need to check fprintf when it is used in this way?
如果没有,这样使用fprintf时是否需要检查?
回答by Jonathan Leffler
The C standard says that the file streams stdin, stdout, and stderrshall be connected somewhere, but they don't specify where, of course.
(C11 §7.21.3 Files ?7:
C 标准说文件流stdin、stdout和stderr应在某处连接,但它们当然没有指定在哪里。(C11 §7.21.3 文件?7:
At program startup, three text streams are predefined and need not be opened explicitly -- standard input (for reading conventional input), standard output (for writing conventional output), and standard error (for writing diagnostic output). As initially opened, the standard error stream is not fully buffered; the standard input and standard output streams are fully buffered if and only if the stream can be determined not to refer to an interactive device.
在程序启动时,三个文本流是预定义的,不需要显式打开——标准输入(用于读取常规输入)、标准输出(用于写入常规输出)和标准错误(用于写入诊断输出)。最初打开时,标准错误流没有完全缓冲;当且仅当可以确定流不是指交互设备时,标准输入和标准输出流才被完全缓冲。
It is perfectly feasible to run a program with the standard streams 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 stdoutand stderr— in contravention of the the standard. It is still reading from /dev/nullin the example, which means it doesn't get any useful data input from stdin.
这一次,它在没有打开文件流的情况下运行,stdout并且stderr违反了标准。它仍在/dev/null示例中读取,这意味着它不会从stdin.
Many a program doesn't bother to check that the standard I/O channels are open. Many a program doesn't bother to check that the error message was successfully written. Devising a suitable fallback as outline by Tim Postand whitey04isn't always worth the effort. If you run the lscommand with its outputs suppressed, it will simply do what it can and exits with a non-zero status:
许多程序并不费心去检查标准 I/O 通道是否打开。许多程序并不费心去检查错误消息是否已成功写入。由Tim Post和whitey04设计一个合适的后备方案并不总是值得的。如果您在ls输出被抑制的情况下运行该命令,它将简单地做它所能做的并以非零状态退出:
$ ls; echo $?
gls
0
$ ls >&- 2>&-; echo $?
2
$
(Tested RHEL Linux.) There really isn't a need for it to do more. 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).
(经过测试的 RHEL Linux。)真的没有必要让它做更多的事情。另一方面,如果您的程序应该在后台运行并写入日志文件,它可能不会向 写入太多内容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; the syslogfunctions all return no status information. You just have to assume that they were successful. It is your last resort, therefore.
请注意,如果您依靠syslog(3)(或POSIX),您将无法知道您的调用是否“成功”;这些syslog函数都没有返回任何状态信息。你只需要假设他们是成功的。因此,这是您的最后手段。
回答by Tim Post
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.
- If both fail, try creating a 'crash.{pid}.log' file that contains information that you'd want in a bug report. 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.
- 如果 fprintf 失败,请尝试 syslog。
- 如果两者都失败,请尝试创建一个“crash.{pid}.log”文件,其中包含您希望在错误报告中提供的信息。启动时检查这些文件是否存在,因为它们可以告诉您的程序之前崩溃过。
- 让网络连接的用户检查允许您的程序提交错误报告的配置选项。
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. But do try to isolate that kind of logic into a small library.
正如whitey04 所说,有时您只需要放弃并尽力不让烟花燃尽。但是一定要尝试将这种逻辑隔离到一个小库中。
For instance:
例如:
best_effort_logger(LOG_CRIT, "Heap corruption likely, bailing out!");
Is much cleaner than a series of ifelseelse ifevery place things could possibly go wrong.
比一系列ifelseelse if可能出错的地方要干净得多。
回答by whitey04
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 (e.g. the OS doesn't have to kill it for being bad and it tells you why it exited [if it can]).
关键是你的应用程序“优雅地”处理它(例如,操作系统不必因为它不好而杀死它,它会告诉你它为什么退出[如果可以的话])。
回答by R.. GitHub STOP HELPING ICE
Yes, of course fprintfto stderrcan fail. For instance stderrcould 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.
是的,当然fprintf要stderr失败。例如,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).
您是否应该检查操作是否失败在很大程度上取决于您是否可以通过检查获得更好的程序行为。在您的情况下,您无法打印错误消息时唯一可以想到的事情是尝试打印另一个(几乎肯定也会失败)或退出程序(这可能比不报告错误更糟糕,但也许不总是)。
回答by sarnold
Some programs that reallywant to log error messages will set up an alternate stackat program start-up to reserve some amount of memory (see sigaltstack(2)that can be used by a signal handler (usually SIGSEGV) to report errors. Depending upon the importance of logging your error, you could investigate using alternate stacks to pre-allocate some chunk of memory. It might not be worth it :) but sometimes you'd give anything for some hintof what happened.
一些真正想要记录错误消息的程序会在程序启动时设置一个备用堆栈以保留一定数量的内存(请参阅信号处理程序(通常)可以使用的sigaltstack(2SIGSEGV) 来报告错误。取决于记录错误的重要性,您可以调查使用备用堆栈来预分配一些内存块。这可能不值得:) 但有时您会给出任何暗示发生了什么的事情。

