fscanf 未能检测到匹配失败。 libc 错误与否?
Posted
技术标签:
【中文标题】fscanf 未能检测到匹配失败。 libc 错误与否?【英文标题】:fscanf fails to detect matching failure. libc bug or not? 【发布时间】:2014-12-22 08:21:03 【问题描述】:问题如下:
#include <stdio.h>
#include <stdlib.h>
int main(void)
float f = 0.0f;
int n = 0;
n = fscanf(stdin, "%f", &f);
printf("n = %d, f = %f\n", n, f);
return 0;
打印出来:
n = 1,f = 100.0000
如果输入字符串是:
100ergs
已提供给stdin
。以下行为发生在 gcc (4.8.1) 和 VS2010(及更低版本)上。这是一个错误,还是我在这里遗漏了什么?因为第 7.19.6.2.19 和 7.19.6.2.20 节中的 c 标准 (c89) 明确指出,由于匹配失败,n 应该等于 0。
UPD。只是一些额外的信息:
1) 标准示例:
http://port70.net/~nsz/c/c99/n1256.html#7.19.6.2p20(感谢 Chris Culter 提供链接)
2) 匹配失败的类似示例,按预期工作:
#include <stdio.h>
#include <stdlib.h>
int main(void)
int hex = 0x0;
int n = 0;
n = fscanf(stdin, "%x", &hex);
printf("n = %d, hexVal = %x\n", n, hex);
return 0;
如果 stdin 包含 0xz 输出是
n = 0, hexVal = 0
【问题讨论】:
不是匹配失败。遇到“e”时匹配停止,“ergs”未解析。如果你需要更细粒度的控制,可以考虑使用strtod
,这当然意味着你必须先从stdin
读取一个字符串。
好的,但是上面部分中的标准确实明确指出,在那种确切的情况下(示例相对相同,输入相同)它是匹配失败。这就是让我感到困惑的地方......
@HighPredator,我不想将您的问题编辑得太远,但您可能想引用 C99 草案的 7.19.6.2.20 并链接到 port70.net/~nsz/c/c99/n1256.html#7.19.6.2p20 以供证明。 count = 0; // "100e" fails to match "%f"
这行很重要。
@ChrisCulter,感谢链接。
没有问题,我是从***.com/a/17015061 得到的 :)
【参考方案1】:
除非他们对最终标准进行了更改,否则您看到的行为是一个错误。 (感谢 HighPredator 的链接)
Difference between scanf() and strtol() / strtod() in parsing numbers.
【讨论】:
这是新事物。我从来没有在任何地方看到过。你能提供一个链接吗?因为我的印象是 scanf group 和 strto.. group 在机械上是不同的功能。 是的,显然它们在机制上确实不同。 ***.com/questions/1425730/… @HighPredator 我误读了链接的草稿。似乎这是一个错误。感谢您指出。【参考方案2】:您正在从流中读取。 fscanf
获取所有可接受的字符...并将其余字符留给下一次读取操作。在 C 中,以下两个 sn-ps 给出相同的结果:
int i, j;
fscanf(stdin, "%d", &i);
fscanf(stdin, "%d", &j);
和
int i, j;
fscanf(stdin, "%d%d", &i, &j);
如果你用1 2
喂食,你会得到i=1
、j=2
您对此有何期待:
float f = 0.0f;
int n = 0;
char c[16];
n = fscanf(stdin, "%f", &f);
printf("n = %d, f = %f\n", n, f);
n = fscanf(stdin, "%15s", c);
printf("n = %d, string = %s\n", n, c);
当使用100erg
喂食时,你会得到:
n = 1, f = 100.0000
n = 1, string = erg
所以当前的fscanf
结果是完全正确的,因为100
可以作为输入浮点数。
【讨论】:
这就是我要指出的。 “所以当前的 fscanf 结果是完全正确的。”就上面的标准示例而言,它不是。其次,根据 6.4.4.2 的描述,100erg 的 100e 部分是一个有效的“前缀”。由于恕我直言,标准要求 scanf 在这种情况下返回零。 看起来我的段落编号与这个不同......无论如何,这就是我在谈论port70.net/~nsz/c/c89/c89-draft.html#3.1.3.1 简而言之,我看到它的方式:100e 是指数形式的浮点值的有效“前缀”(就像十六进制的 0x)然后,在它之后,标准输入不包含有效的数字部分.在这种情况下,应该发生匹配的失败情况(就像十六进制一样)并且应该返回零。 @HighPredator :我们处于黑暗的一面。我在 MSVC2008 中尝试过,它拆分了100e
(给出100.
)和rg
,但是clang 3.1 和gcc 4.2.1(FreeBSD 9.0)拆分了100
和erg
。我没有最近可用的编译器来查看它是否随它们而变化。以上是关于fscanf 未能检测到匹配失败。 libc 错误与否?的主要内容,如果未能解决你的问题,请参考以下文章
Cloudera安装未能检测到CentOS上的root特权我试图将新主机添加到CentOS集群中。安装失败,状态为“安装失败。无法检测root特权”。我知道Cloudera需要用户具有无密码特权(“需
Firestore NSArray 到 Swift.Array 匹配错误