为什么阅读’+’和’ – ‘不适用于Linux?

我有这个代码片段,它将1 + 2 * 3等算术表达式读成整数和字符:

 int main() { int d, flag = 0; char c; while ((flag = scanf("%d", &d)) != EOF) { if (flag == 1) // if integer was read sucessfully { // an integer has been read into variable 'd' printf("%d,", d); } else // else if it was a character { // then read char into variable 'c' c = getchar(); printf("%c,", c); } } } 

现在这个代码在Windows和MacOS上使用MingGW进行编译时可以正常工作,但不知何故在Linux上,它的字符+-都没有正确读取。

样品运行:
输入: 1 * 2 * 3
输出: 1,*,2,*,3,

输入: 1 + 2 - 3
输出: 1, ,2, ,3,

输入: 1 ++ 2 -- 3
输出: 1,+,2,-,3

不知何故, +-字符被读作空格。 但是如果我们放双++--它就有效。 再次,这只发生在Linux上和几乎所有在线IDE上编译时。 令人费解的是为什么只有+-字符? 可能是他们被认为是积极和消极的迹象?

当你进入

 1 + 2 

扫描第一个数字。 当scanf尝试扫描第二个数字时,它首先扫描+ (这是一个带有一元+的数字的有效开始),但是在[space] +偶然发生后失败:失败

即使扫描失败,也不会消耗[space] ,但是+是。 这解释了为什么单独的+-字符被消耗但没有看到。

使用**不会被消耗,因为数字不能以*开头

你在MinGW上有不同的事实对我来说是一个谜,我在MinGW上,我得到了你所描述的“错误”行为。 但我的假设是你使用的标准库比标准实现更“智能”,并在找到它时放回+-所以getchar之后可以正确读取它。

我建议您尝试使用-D__USE_MINGW_ANSI_STDIO=1来编译代码以确保gcc不使用Microsoft scanf实现,并且您应该再次获得“错误”行为(我不确定是否存在解析拙劣数字的标准BTW)

你的scanf方法确实注定了,因为:

  • 您可以在上面遇到的角柜
  • 事实上,如果你输入1 +2 (没有空格),那么也不会读取符号,因为它是第二个数字的一​​部分。

这里最好的方法是使用char自定义词法分析器读取char。

Jean-FrançoisFabre正确地解释了实际发生的事情,但我的观点是,标准中没有具体说明在这种情况下会发生什么。

C11的草案n1570表示在7.21.6.2 fscanf函数

12转换说明符及其含义是:
d匹配可选带符号的十进制整数,其格式与strtol函数的主题序列的预期格式相同,基本参数的值为10。 相应的参数应该是指向有符号整数的指针。

strtol在7.22.1.4中描述了strtol,strtoll,strtoul和strtoull函数(强调我的)

描述
2 strtol,strtoll,strtoul和strtoull函数分别将nptr指向的字符串的初始部分转换为long int,long long int,unsigned long int和unsigned long long int表示。 首先,它们将输入字符串分解为三个部分:初始的,可能为空的空白字符序列(由isspace函数指定), 类似于由base的值确定的某个基数表示的整数的主题序列 ,以及一个或多个无法识别的字符的最终字符串,包括输入字符串的终止空字符。 然后,他们尝试将主题序列转换为整数,并返回结果。

我无法在标准中的任何地方找到完全类似十进制整数的内容。 很明显,正数和负数都有,并且前缀加号( + )的数字也可以。 但是没有指定加号和减号( +- )是否类似于十进制整数。

如果一个实现决定他们这样做, %d说明符将单独使用+-符号,如果它确定它们没有,它将把它们留在流中。

由于scanf(“%d”,&d),’+ 2’被扫描到’d’。 您可以尝试使用’1-2’并看到’ – ‘也无法显示。