stdio 错误检测:ferror 与 fclose

stdio error detection: ferror versus fclose

在标准 C 中,如何可靠地检查写入标准 I/O 流的所有输出是否已成功保存到磁盘?

C 标准声明 fclose 将 return 0 成功,或 EOF 如果 "any errors were detected"。

但这是否意味着 "any errors were detected during the fclose call"?或者它的意思是"any errors were detected since the last call to clearerr"?

换句话说,一个程序检查fclose的return值就足够了吗,还是还需要检查ferror?是否有任何实现,如果 ferror return 非零,随后对 fclose 的调用可能 return 0?

fflush也是如此:如果fflush returns 0,后续调用ferror是否总是这样return 0,并且如果 fflush returns EOF,对 ferror 的后续调用将 return 非零?是否有任何实现不是这种情况?

(当然,我不是在考虑停电,gremlins等,是的,需要保证持久性的程序应该使用fsync,但这超出了标准C的范围。)

在没有更好的答案的情况下:

  • 标准告诉我 ferror() return 是 'error indicator' 的状态,它被定义为 状态.

  • 标准告诉我很多关于何时设置 'error indicator',但没有告诉我什么时候可以清除它——除了 clearerr()rewind() 定义为清除它。

  • 标准没有告诉我如果在调用函数时设置了 'error indicator' 任何函数(ferror() 除外)应该做什么。

你的问题似乎是基于这样的可能性,即一旦出现错误就会设置'error indicator'并且只有在明确清除时才清除(它是"latched")。在这种情况下:

  1. ferror() 会告诉您某些 stdio 函数发生错误,因为 fopen()(或最近的 clearerr()rewind()).

    我认为标准没有要求,但没有说可能不需要。

  2. fclose() 可能 return 一个错误 (a) 如果在关闭时发生错误, (b) 如果 'error indicator' 已经设置。

    而且,如果是这样,成功的 fclose() 将意味着一切过去和现在都很好,因为 fopen()(或最近的 clearerr()rewind() ).

    我认为标准没有要求,但没有说可能不需要。

如果标准没有明确要求某些东西,也没有明确排除某些东西,我们自己就是一只既不活也不死的猫。

简而言之,我认为标准不会以某种方式回答您的任何问题。

标准的保守解读是:

  • 在每次 stdio 函数调用后立即检查错误,并进行相应处理。

  • 一般来说,在读取或写入错误后,放弃并关闭流是显而易见的反应。

    fclose() 可能 return 当前错误(再次),或新错误或根本没有错误。如果要 returned 错误,我会 return 原来的 read/write 错误。在报告错误的地方,我会报告原始的 read/write 错误和由 fclose() 编辑的任何错误 return。

  • 如果决定继续 inputting/outputting,'error indicator' 可能(或可能不会)影响进一步的功能,并且可能(或可能不会)被大多数人清除更多功能...

    ...所以最好清除 clearerr(),以避免任何可能的混淆。

    但是,我几乎确信 fgetc() 必须:

    一个。如果 'error indicator' 已经设置,则立即放弃(并再次设置 errno

    或:

    b。 clear 'error indicator' -- 如果不是,if fgetc() then succeeds and returns EOF 是什么意思?

    其他get和put char和wide-char也是如此。所有其他函数并非如此,其中 return 值不明确。

  • 不要期望 ferror() 告诉您任何关于在最近的 stdio 函数调用之前可能发生的错误。

    很明显,ferror() 对于错误 return 与 EOFWEOF return 相同的少数函数很有用。 (如果可能出现值为 EOFWEOF 的字符,则 feof() 很有用!)。

    不太清楚 ferror() 和 'error indicator' 是否对其他任何东西有用。


FWIW:我在标准中找到的内容

标准说 (§7.21.7.1) fgetc():

  1. If the end-of-file indicator for the input stream pointed to by stream is not set and a next character is present, the fgetc function obtains that character as an unsigned char converted to an int and advances the associated file position indicator for the stream (if defined).

Returns

  1. If the end-of-file indicator for the stream is set, or if the stream is at end-of-file, the end-of-file indicator for the stream is set and the fgetc function returns EOF. Otherwise, the fgetc function returns the next character from the input stream pointed to by stream. If a read error occurs, the error indicator for the stream is set and the fgetc function returns EOF 293).

293) An end-of-file and a read error can be distinguished by use of the feof and ferror functions.

我注意到,如果在调用函数时设置了 'end-of-file indicator',它应该做什么是非常清楚的。相反,如果 'error indicator' 已经设置,它不会以某种方式说明 fgetc() 应该做什么:

  1. fgetc() 应该立即失败吗?

    如果是这样,是否应将 errno 设置为与首次设置 'error indicator' 时相同的值?

    但是,如果 'error indicator' 之前由(比如)EINTR 设置,那么注意它就没有意义了。

否则:

    如果此调用成功,
  1. 是否应该 fgetc() 清除 'error indicator'?

    如果不是,则'error indicator'可以被认为是"latched"状态,表明在上次清除后的某个时间发生了错误。

    同样,如果 'error indicator' 之前由(比如)EINTR 设置,那么保留它是没有意义的。请注意,C 对 EINTR 一无所知...因此实现可以自由地使用 'error indicator' 执行不同的操作,具体取决于它的设置方式。

    AND,如果 fgetc() 恰好获取值为 EOF 的字符或恰好命中实际 EOF,则 NOT 清除 'error indicator' 将是一个错误!

标准说 (§7.21.7.3) fputc():

  1. The fputc function writes the character specified by c (converted to an unsigned char) to the output stream ...

Returns

  1. The fputc function returns the character written. If a write error occurs, the error indicator for the stream is set and fputc returns EOF.

同样,如果 'error indicator' 已经设置,这并没有指定 fputc() 应该做什么。

同样适用于fgetwc()fputwc()

每个其他 input/output 函数都被定义为工作 "as if" 它们被重复 fgetc()fputc()fgetwc() 和 fputwc()`。

标准说 (§7.21.10.3) ferror():

  1. The ferror function tests the error indicator for the stream pointed to by stream.

Returns

  1. The ferror function returns nonzero if and only if the error indicator is set for stream.

就是这样。上面的脚注 293 是关于如何使用 ferror() 和 'error indicator' 的最具体指南。

fflush() (§7.21.5.2)、fseek() (§7.21.9.2) 和 fsetpos() (§7.21.9.3) 都定义为设置 'error indicator' 如果出现错误。

rewind() (§7.21.9.5) 和 clearerr() (§7.21.10.1) 定义为清除 'error indicator'.

我没有找到对 'error indicator' 的其他引用。