【发布时间】:2013-08-19 15:29:14
【问题描述】:
是否需要在调用abort() 之前显式刷新输出流以避免丢失输出?
据我了解,stderr 没有缓冲,所以在输出到stderr/cerr 后调用abort 应该没问题。 stdout/cout 或者我打开的文件怎么样?
PS。我在 Linux 环境中工作(如果重要的话)。
【问题讨论】:
是否需要在调用abort() 之前显式刷新输出流以避免丢失输出?
据我了解,stderr 没有缓冲,所以在输出到stderr/cerr 后调用abort 应该没问题。 stdout/cout 或者我打开的文件怎么样?
PS。我在 Linux 环境中工作(如果重要的话)。
【问题讨论】:
是的,它是必需的,但不,它可能是不可能的。如果您正在从异步信号上下文中止,则调用 fflush 会调用未定义的行为。通常,如果调用abort 的原因是您在程序中检测到不一致的状态,则存在stdio 状态也被破坏的风险,因此调用fflush 是不安全的。
一般来说,如果您由于程序无法处理的情况而终止,您应该使用exit(1),并且只有在检测到您的程序被调用时才使用abort()(没有fflush)已经有未定义的行为,
更多细节:
C 标准允许实现将 stdio 流作为 abort 的一部分刷新 (C11 7.22.4.1:):
是否刷新带有未写入缓冲数据的打开流、关闭打开流或删除临时文件是实现定义的。
但是,如果从信号处理程序调用abort,这并不能消除这种要求。因为,从实际的角度来看,如果 abort 是从中断了缓冲区处于不一致状态的 stdio 代码的信号处理程序调用的,通常不可能刷新缓冲区,因此任何尝试使用此允许的实现都可能是错误的.
abort 的 Linux 手册页的当前版本错误地指出:
如果 abort() 函数导致进程终止,则所有打开的流都将关闭并刷新。
对当前行为更正确的说法是,已尝试刷新,但可能会失败或损坏您的数据。根据此线程,此错误目前正在 glibc 中修复(也许修复已经提交...?):
http://www.sourceware.org/ml/libc-alpha/2013-05/msg00207.html
【讨论】:
abort,exit(EXIT_FAILURE)就足够了吗?
exit(EXIT_FAILURE) 应该足以捕获用户错误。 abort 应该只用于更严重的情况。例如,如果您检测到您的应用程序完全耗尽内存。
abort 和exit(1) 都是不良行为,因为内存不足。这里真的没有必要更喜欢abort,因为程序处于调用exit仍然安全的状态,但abort的恶意可能会稍微小一些,因为调用代码可能会捕获SIGABRT和@987654341 @ 退出因内存不足而中止的错误代码。 :-) 如果你在这样的非 UB 情况下使用abort,我认为最好先调用fflush(0)。
Stdout 是缓冲的,例如,您使用 ofstream 打开的文件也是如此。您必须使用刷新操纵器显式刷新它们
【讨论】:
stdout一些诡计。
main 的开头使用setvbuf 或setbuf 即可获得无缓冲的stdout。