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=1j=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)拆分了100erg。我没有最近可用的编译器来查看它是否随它们而变化。

以上是关于fscanf 未能检测到匹配失败。 libc 错误与否?的主要内容,如果未能解决你的问题,请参考以下文章

Cloudera安装未能检测到CentOS上的root特权我试图将新主机添加到CentOS集群中。安装失败,状态为“安装失败。无法检测root特权”。我知道Cloudera需要用户具有无密码特权(“需

Firestore NSArray 到 Swift.Array 匹配错误

未检测到 xpath 跨度

在'identityPoolId'处检测到的验证错误未能满足约束

由于警告,CMake 未能检测到 pthread

错误 ITMS-90085:“二进制文件中没有架构。Lipo 未能检测到捆绑可执行文件中的任何架构。”