我必须在解析它们时从C中的流中单独读取字符和子字符串。我还想检查输入错误。显而易见的方法是:
c = fgetc(f);
if(ferror(f)) {
puts(strerror(errno));
exit(1);
}
/* do something with c */
c = fgetc(f);
if(ferror(f)) {
puts(strerror(errno));
exit(1);
}
/* do something with c */
等。但是,如果我可以执行所有输入操作并稍后检查错误指示器,它将更加实用和快速(在没有错误的非特殊情况下):
c = fgetc(f);
/* do something with c */
c = fgetc(f);
/* do something with c */
if(ferror(f)) {
puts(strerror(errno));
exit(1);
}
如果设置了f的错误指示符,那么当fgetc(),scanf()等输入操作简单地通过no-ops时,这是可能的。比如说,第一个fgetc()中出现错误,因此第二个fgetc()是一个失败的no-op,但既不改变f的错误指示也不改变errno。
可能会询问有关输出功能的类似问题。
我的问题是:这是stdio函数的行为吗?我可以在所有操作之后检查ferror(f)并获得errno然后如果我确定所有那些“用c做某事”不会改变errno吗?
谢谢!
答案 0 :(得分:0)
不,这些不是errno
的定义语义。
仅当调用的返回值指示错误时(即大多数系统调用的
-1
;大多数库函数的-1
或NULL
),其值才有意义;成功的函数允许更改errno。
这意味着如果你要进行两次I / O操作,第一次失败,第二次是" no-op" (比如读取零字节)它可以成功并选择清除errno
,从而删除第一次调用设置的错误。
答案 1 :(得分:0)
回答我自己的问题,实现我正在寻找的可靠方法似乎是编写一个包装函数myfgetc(),正如Michael Walz建议的那样,以及一个全局变量myerrno:
__thread int myerrno = 0;
int myfgetc(FILE *f) {
int c;
if(myerrno)
return EOF;
if((c = fgetc(f)) == EOF)
myerrno = errno;
return c;
}
将存储类__thread添加到myerrno,以便每个线程都有自己的myerrno。如果程序是单线程的,可以省略它。
答案 2 :(得分:0)
...这是stdio函数的行为吗(在第一个fgetc()中发生错误,因此第二个fgetc()是失败的无操作)?
不-不是禁忌。
FILE
具有:“一个错误指示器,记录是否发生了读/写错误”(C11dr§§7.21.1 2),而不是发生了错误 just 。这是一个累积读取错误历史的标志。
对于fgetc()
和朋友,
如果发生读取错误,则将设置流的错误指示符,并且
fgetc
函数将返回EOF
。 C11dr§7.21.7.1 3。
由于输入错误而导致的EOF
返回与由于文件结尾而引起的EOF
不同。后者具有或“如果设置了流的文件结束指示符,则或如果流在文件末尾,则设置结束流的-file指示符已设置,并且fgetc
函数返回EOF
“。 EOF
由于输入错误而没有或。
我认为这意味着流的错误指示符可以为真,并且fgetc()
不返回EOF
,因为刚刚读取的字节没有错误。 / p>
How a stream error indicator affects following input code?可能有用。
我可以在所有操作后检查
ferror(f)
并得到errno
,然后确定所有“用c做某事”都不会改变errno
吗?
errno
在这里没什么用。 C没有将任何I / O函数指定为肯定设置errno
-这是某些编译器的扩展。 C明确禁止标准函数清除errno
。
是的,代码可以检查ferror(f)
来查看过去是否曾经发生错误。无需检查errno
。
要清除错误指示器和文件结尾,请研究clearer()
。