繁体   English   中英

fscanf:如果没有返回EOF,可能是错误还是EOF?

[英]fscanf: is error or EOF possible without EOF returned?

我有一个C ++程序,它从一个文件中读取,我希望它有一堆格式相同的记录。 如果我遇到意外的事情,我想停止阅读是否意味着格式错误的记录或输入失败,我想区分这些不同的条件。

我已经看到了这个答案并查看了fscanf() 文档 ,我不确定fscanf()可以指示错误或EOF而不返回EOF。 从我这两个环节的理解有可能发生错误或EOF即使发生fscanf()返回值为0或更大的值,所以我得打个电话ferror()feof()无论什么价值的fscanf()返回。 我似乎无法找到EOF的返回值如何对调用者有任何用处。

假设我希望我的文件有一堆包含4个值的记录。 下面的代码会正确处理文件的任何结尾和输入错误条件吗?

  int ret;
  int field1;
  int field2;
  int field3;
  int field4;
  while ((ret = fscanf(pFile, "%d %d %d %d", &field1, &field2, &field3,
                       &field4)) == 4) {
    // do whatever with fields
  }
  if (ferror(fp)) {
    // some input error occurred
  } else if (feof(fp)) {
    // end of file occurred
  } else {
    assert(ret != EOF);
    // encountered record that didn't match expected format
  }

更新:所以我将添加来自cppreference的文档,因为在描述哪些条件不再导致返回EOF时似乎略有不同。

没有退回EOF会出现错误或EOF吗?

是的。 您还可以获得0到3之间的返回值.cplusplus.com有点臭名昭着。 我们来看看cppreference.com的页面

返回值:成功分配的接收参数数(如果在分配第一个接收参数之前发生匹配失败,则可能为零),如果在分配第一个接收参数之前发生输入失败,则为EOF。

有几种不同的场景。 让我们把它分解成案例:

  1. 如果它已成功分配给第一个接收参数,那么您将获得正值,保证。 假设它被分配给两个变量,然后命中EOF。 它将返回2并且feof()将返回true。

  2. 否则,如果它尚未分配给第一个接收参数并获得匹配失败,则它将返回0 什么是匹配失败? 那时它匹配像%d这样的说明符并且没有得到有效的整数。 如果输入是foobar%d将无法匹配。

    或者,不太常见的是,当它正在寻找文字字符并且没​​有看到它时。 例如,如果您的格式字符串要求将每个数字括在括号中( "[%d] [%d] [%d] [%d]" ),那么如果输入没有以[开头"[%d] [%d] [%d] [%d]" ,它将返回0

  3. 否则,如果它尚未分配给第一个接收参数并获得EOF或读取错误,则它将返回EOF 请注意, 读取错误与匹配错误不同。 读取错误是指操作系统返回尝试从磁盘读取的I / O错误。

    EOF的返回值表示文件结束或I / O错误。 如果您不关心这种区别,您可以放弃循环并继续使用该程序。 但是,如果要在ferror()上打印错误消息并将feof()视为成功,则检查ret是不够的; 你必须调用其中一个或两个功能。 如果你想这样做,这取决于你。

假设我希望我的文件有一堆包含4个值的记录。 下面的代码会正确处理文件的任何结尾和输入错误条件吗?

是的。 对我来说看上去很好。


对于它的价值,我建议不要使用scanf()fscanf() 它们很复杂,并且使处理输入错误比必要时更加困难。 这个问题是一个很好的证明。 最好使用fgets()读取整行,使用sscanf()来解析它。 这样一来,如果输入结果不好,你就不会有局部线条干扰未来的读取。

我发现通过示例更容易解释fscanf函数族的返回值。

// The string contains valid data given the format specifier.
// Expect ret to be 1.
int ret = sscanf("10", "%d", &n);

// The string contains data but not what the user expects to see.
// Expect ret to be 0.
int ret = sscanf("abcd", "%d", &n);

// The string contains no data .
// Expect ret to be EOF.
int ret = sscanf("", "%d", &n);

在所有这些情况下,如果您有前导空格,则可以预期相同的行为。

// Expect ret to be 1.
int ret = sscanf("  10", "%d", &n);

// Expect ret to be 0.
int ret = sscanf("  abcd", "%d", &n);

// Expect ret to be EOF.
int ret = sscanf("  ", "%d", &n);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM