【问题标题】:File operations with error indicator set设置了错误指示器的文件操作
【发布时间】:2016-02-25 09:02:58
【问题描述】:

在解析它们时,我必须从 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);
}

如果 fgetc()、scanf() 等输入操作在设置 f 的错误指示符时是简单的 passthrough no-ops 时,这将是可能的。比如说,第一个 fgetc() 发生错误,因此第二个 fgetc() 是一个空操作,它失败但既不改变 f 的错误指示符也不改变 errno。

可能会询问有关输出函数的类似问题。

我的问题是:这是 stdio 函数的行为吗?我可以在所有操作后检查 ferror(f) 并获取 errno,那么如果我确定所有那些“用 c 做某事”的人不会改变 errno?

谢谢!

【问题讨论】:

  • 您可以编写一个 myfgetc 函数来完成您所描述的操作。
  • 当然,一个包装函数。一个明显的解决方案!
  • 后续函数调用失败,但其他函数也可能改变errno的值——不管它们是否失败。因此,您使用建议的方案失去了对 errno 的准确跟踪,但它可以正常工作。
  • fgetc 返回EOF 之前,没有理由调用ferror
  • @William Pursell 即使 fgetc() 不返回 EOF,调用 ferror() 也没有错。如果设置了 ferror(),那么我知道 fgetc() 返回 EOF。

标签: c


【解决方案1】:

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

引用this manual page:

它的值只有在调用的返回值指示错误时才有意义(即,大多数系统调用中的-1;大多数库函数中的-1NULL);允许成功的函数更改 errno。

这意味着如果您要执行两次 I/O 操作,其中第一次失败,第二次是“无操作”(如读取零字节),它可能会成功并选择清除 errno,从而丢弃第一次调用设置的错误。

【讨论】:

  • 我认为如果设置了 f 的错误指示符,所有后续的 fgetc(f) 调用都应该失败。我错了吗?我希望 errno 在这种情况下不会受到影响。
  • @user1542207 我希望 errno 在这种情况下不会受到影响。 你打算基于 hope 编写代码吗?
  • @Andrew Henle 不,我计划根据我来这里寻找的规范编写代码。但第一步永远是希望。
  • 标准 C 库(或标准 POSIX library)中没有函数将 errno 设置为零。 C11 标准规定:程序启动时初始线程中errno 的值为零(其他线程中errno 的初始值为不确定值),但绝不会被任何库函数设置为零. errno 的值可以通过库函数调用设置为非零,无论是否存在错误,前提是本国际标准的函数描述中没有记录 errno 的使用。
【解决方案2】:

回答我自己的问题,似乎实现我正在寻找的可靠方法是编写一个包装函数 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。如果程序是单线程的,可以省略。

【讨论】:

    【解决方案3】:

    ...这是(第一个 fgetc() 中发生错误,因此第二个 fgetc() 是失败的无操作)stdio 函数的行为吗?

    不 - 不是无操作。

    FILE 具有:“记录是否发生读/写错误的错误指示器”(C11dr § 7.21.1 2),而不是刚刚发生了错误。它是一个累积读取错误历史的标志。

    献给fgetc()和朋友们,

    如果发生读取错误,则设置流的错误指示符并且fgetc 函数返回EOF。 C11dr § 7.21.7.1 3.

    由于输入错误而返回的EOF 与由于文件结束而导致的EOF 不同。后者有一个“如果设置了流的文件结束指示符,如果流处于文件结束,则结束- 流的文件指示符已设置,fgetc 函数返回 EOF"。 EOF 由于输入错误没有

    我将此解释为暗示流的错误指示符可以为真,并且fgetc() 不会返回EOF,因为刚刚读取的字节没有错误。

    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()

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-08-29
      • 2018-10-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多