fscanf:如果不返回 EOF,是否可能出现错误或 EOF?
fscanf: is error or EOF possible without EOF returned?
我有一个 C++ 程序,它从我希望有一堆格式相同的记录的文件中读取。如果遇到意外情况,无论是记录格式错误还是输入失败,我都想停止阅读,我想区分这些不同的情况。
我已经看到 this answer and looked at the fscanf()
documentation 但我不确定 fscanf()
是否可以指示错误或没有 returning EOF 的 EOF。根据我对这两个链接的理解,即使 fscanf()
return 的值为 0 或更大,也可能会发生错误或 EOF,因此我必须调用 ferror()
和 feof()
不管什么值 fscanf()
returns。我似乎无法找到 EOF 的 return 值对调用者有何用处。
假设我希望我的文件包含一堆具有 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 被 returned 时似乎略有不同。
Is error or EOF possible without EOF returned?
是的。您还可以获得介于 0 和 3 之间的 return 值。cplusplus.com 有点草率。让我们来看看cppreference.com's page。
Return value: Number of receiving arguments successfully assigned (which may be zero in case a matching failure occurred before the first receiving argument was assigned), or EOF if input failure occurs before the first receiving argument was assigned.
有几种不同的情况。让我们将其分解为案例:
如果它已成功分配给第一个接收参数那么你将得到一个正值,保证。假设它被分配给两个变量然后命中 EOF。它将 return 2
和 feof()
将 return 为真。
否则,如果它没有分配给第一个接收参数并且匹配失败它将return0
.什么是匹配失败?那是当它匹配 %d
之类的说明符并且没有获得有效整数时。如果输入是 foobar
那么 %d
将无法匹配。
或者,不太常见的情况是,当它正在寻找一个文字字符但没有看到它时。例如,如果您的格式字符串希望每个数字都包含在方括号 ("[%d] [%d] [%d] [%d]"
) 中,那么如果输入不是以 [
.[= 开头,它将是 return 0
32=]
否则,如果它没有分配给第一个接收参数并得到 EOF 或读取错误,它将returnEOF
。请注意,read 错误不同于 matching 错误。读取错误是当 OS return 尝试从磁盘读取时出现 I/O 错误。
EOF
的 return 值表示 end-of-file 或 I/O 错误。如果您不关心区别,您可以放弃循环并继续执行该程序。但是,如果您想在 ferror()
上打印一条错误消息并将 feof()
视为成功,那么检查 ret
是不够的;您必须调用其中一个或两个函数。想不想做就看你自己了
Say I expect my file to have a bunch of records with 4 values. Would the code below properly handle any end of file and input error conditions?
是的。我觉得不错。
鉴于其价值,我建议不要使用 scanf()
和 fscanf()
。它们很复杂,使处理输入错误变得比必要的更困难。这个问题就是一个很好的示范。最好使用 fgets()
来读取整行并使用 sscanf()
来解析它。这样,如果有错误的输入,您就不会有部分行干扰未来的读取。
我发现通过示例更容易解释 fscanf
函数族的 return 值。
// 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);
我有一个 C++ 程序,它从我希望有一堆格式相同的记录的文件中读取。如果遇到意外情况,无论是记录格式错误还是输入失败,我都想停止阅读,我想区分这些不同的情况。
我已经看到 this answer and looked at the fscanf()
documentation 但我不确定 fscanf()
是否可以指示错误或没有 returning EOF 的 EOF。根据我对这两个链接的理解,即使 fscanf()
return 的值为 0 或更大,也可能会发生错误或 EOF,因此我必须调用 ferror()
和 feof()
不管什么值 fscanf()
returns。我似乎无法找到 EOF 的 return 值对调用者有何用处。
假设我希望我的文件包含一堆具有 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 被 returned 时似乎略有不同。
Is error or EOF possible without EOF returned?
是的。您还可以获得介于 0 和 3 之间的 return 值。cplusplus.com 有点草率。让我们来看看cppreference.com's page。
Return value: Number of receiving arguments successfully assigned (which may be zero in case a matching failure occurred before the first receiving argument was assigned), or EOF if input failure occurs before the first receiving argument was assigned.
有几种不同的情况。让我们将其分解为案例:
如果它已成功分配给第一个接收参数那么你将得到一个正值,保证。假设它被分配给两个变量然后命中 EOF。它将 return
2
和feof()
将 return 为真。否则,如果它没有分配给第一个接收参数并且匹配失败它将return
0
.什么是匹配失败?那是当它匹配%d
之类的说明符并且没有获得有效整数时。如果输入是foobar
那么%d
将无法匹配。或者,不太常见的情况是,当它正在寻找一个文字字符但没有看到它时。例如,如果您的格式字符串希望每个数字都包含在方括号 (
"[%d] [%d] [%d] [%d]"
) 中,那么如果输入不是以[
.[= 开头,它将是 return0
32=]否则,如果它没有分配给第一个接收参数并得到 EOF 或读取错误,它将return
EOF
。请注意,read 错误不同于 matching 错误。读取错误是当 OS return 尝试从磁盘读取时出现 I/O 错误。EOF
的 return 值表示 end-of-file 或 I/O 错误。如果您不关心区别,您可以放弃循环并继续执行该程序。但是,如果您想在ferror()
上打印一条错误消息并将feof()
视为成功,那么检查ret
是不够的;您必须调用其中一个或两个函数。想不想做就看你自己了
Say I expect my file to have a bunch of records with 4 values. Would the code below properly handle any end of file and input error conditions?
是的。我觉得不错。
鉴于其价值,我建议不要使用 scanf()
和 fscanf()
。它们很复杂,使处理输入错误变得比必要的更困难。这个问题就是一个很好的示范。最好使用 fgets()
来读取整行并使用 sscanf()
来解析它。这样,如果有错误的输入,您就不会有部分行干扰未来的读取。
我发现通过示例更容易解释 fscanf
函数族的 return 值。
// 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);