【发布时间】:2019-04-15 19:02:03
【问题描述】:
每个流都有“一个错误指示器,记录是否发生了读/写错误”。
它通常由各种函数设置,通常很少:fgetc(), fflush(), fseek(), ...。
通过各种功能清除:rewind(), clearerr(), fopen(), ...。
int ferror(FILE *stream) 报告状态。
当且仅当为
stream设置错误指示符时,ferror函数才返回非零值。
在这种情况下,肯定是刚刚发生了输入错误。
if (!ferror(istream)) {
int ch = fgetc(istream);
if (ch == EOF && ferror(istream)) {
puts("Input error just occurred");
}
}
深入探索fgetc(),fgetc() 不会返回EOF,因为设置了错误指示器,而是因为“如果发生读取错误”或文件结尾相关的原因1。通常一旦发生错误(例如串行流上的奇偶校验错误),代码不会在不清除错误的情况下继续读取,但要考虑当它继续时会发生什么。
我看到了 8 种情况:错误指示符在fgetc() 之前设置/清除,fgetc() 是否返回EOF,而后面的ferror() 可能为真或不是。
int e1 = !!ferror(istream);
int eof = fgetc(istream) == EOF;
int e2 = !!ferror(istream);
假设没有 UB,是 8 种可能中的 5 种,而不是 3 种意外的?尤其是设置了错误指示器的有效输入可能吗? 2支持>
e1 eof e2
0 0 0 Normal reading of valid data
0 0 1 Unexpected
0 1 0 End-of-file
0 1 1 Input error
1 0 0 Unexpected
1 0 1 Normal reading of valid data with error indicator set!
1 1 0 Unexpected
1 1 1 Input error or end-of-file
在输入操作之前设置错误指示器,事情变得复杂,事先清除它可以简化代码。然而,这可以防止错误指示器累积。
如果代码没有事先清除 错误指示器,并且想要检测输入的 行 是否有罕见的输入错误,那么测试 @ 似乎是有意义的987654341@ 而不是ferror() 来检测。
检查ferror() 是否可能具有误导性? 还是我错过了有关错误指示器的某些内容?
char buf[80];
for (int i=0; i<(80-1); i++) {
int ch = fgetc(stdin);
if (ch == EOF) {
if (ferror(stdin)) {
puts("Input error or (Prior input error and end of file occurred)"); // ambiguous
}
if (feof(stdin)) {
puts("End of file occurred");
} else {
puts("Input error occurred"); // ferror() test not needed
i = 0; // ignore prior input
}
break;
}
if (ch == '\n') break;
buf[i++] = ch;
}
buf[i] = 0;
类似的问题
File operations with error indicator set
。这个未回答的问题集中在累积错误指示符而不测试fgetc() 返回值(答案冒险进入errno 并制作用户错误标志),而这个问题试图简单地消除fgetc() 的歧义。
fgetc(): Is it enough to just check EOF? 不解决在fgetc() 之前设置的错误指示器。
类似的问题适用于输出和 I/O 流,但这个问题侧重于输入流。
1int fgetc(FILE *stream) 退货
如果设置了流的文件结束指示符,或者如果流处于文件结束位置,则设置流的文件结束指示符并且
fgetc函数返回@987654351 @。否则,fgetc 函数从stream指向的输入流中返回下一个字符。如果发生读取错误,则设置流的错误指示符并且fgetc函数返回EOF。 C11dr §7.21.7.1 2
2 案例 0-1-0、1-1-1。似乎UCHAR_MAX == UINT_MAX,一个unsigned char,可以返回并等同于EOF,而不是由于文件结束或输入错误。
【问题讨论】:
-
您是在寻找基于标准的答案(可能是language-lawyer)还是实用的答案?
-
@NominalAnimal 更接近于基于标准,而不是仅仅实用,因为我试图预测 错误指示器 的奥秘来解决:当
fgetc()返回EOF时,是由于到最近的错误、文件结尾、一些宽unsigned char或 其他东西? LL 已添加。 -
FWIW,对于 glibc,它总是由于检测到新的文件结尾或错误情况,因为
fgetc()/getc()/getchar()函数从不检查错误标志。 -
@NominalAnimal glibc 是否还会在现有文件结束标志上返回
EOF而不仅仅是新的文件结束标志? -
glibc
fgetc的行为在 2.28 版中已更改,请参阅 sourceware.org/ml/libc-alpha/2018-08/msg00003.html 和 sourceware.org/bugzilla/show_bug.cgi?id=1190 。我们确实认为 7.21.7p2,3 规定了“粘性 EOF”——该更改被描述为“纠正 [ing] 一个长期存在的 C99 一致性错误”。 (但是,EOF 指示符和错误指示符是两个独立的位。)
标签: c error-handling language-lawyer