设置错误指示器的文件操作

时间:2016-02-25 09:02:58

标签: c

我必须在解析它们时从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吗?

谢谢!

3 个答案:

答案 0 :(得分:0)

不,这些不是errno的定义语义。

引用this manual page

  

仅当调用的返回值指示错误时(即大多数系统调用的-1;大多数库函数的-1NULL),其值才有意义;成功的函数允许更改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()