为什么编译器以不同的方式对待i +++++ i和i +++ i

时间:2013-11-12 07:25:03

标签: c expression

int i=5;
printf("%d",i+++++i);

这会产生错误,但是:

printf("%d",i+++i);

给出输出11.在这种情况下,编译器将其读作:

printf("%d",i+ ++i);

为什么这不是在第一个表达式中完成的?即:

printf("%d",i+++++i); 

3 个答案:

答案 0 :(得分:2)

由于运算符优先级i++++++i被视为(i++)++ + i)。这会产生编译器错误,因为(i++)不是左值。

答案 1 :(得分:1)

根据语言specifications§6.5

,在两个序列点之间多次修改同一个变量是未定义行为
  

在上一个和下一个序列点之间,对象应具有其存储值   通过表达式的评估最多修改一次。此外,先前的价值   只读是为了确定要存储的值。(71)


  

71)此段落呈现未定义的语句表达式,例如

i = ++i + 1;
a[i++] = i;
  

允许

i = i + 1;
a[i] = i;

答案 2 :(得分:0)

printf("%d",i+++++i);中,源文本i+++++i首先根据此规则从C 2011(N1570)进行处理6.4 4:

  

如果输入流已被解析为预处理令牌,直到给定字符,则下一个预处理令牌是可构成预处理令牌的最长字符序列...

这导致词法分析以这种方式进行:

  • i可以是令牌,但i+不能,因此i是下一个令牌。这留下了+++++i
  • +++都可以是令牌,但+++不能。由于++是可能是令牌的最长序列,因此它是下一个令牌。这留下了+++i
  • 出于同样的原因,++是下一个标记。这留下了+i
  • +可以是令牌,但+i不能,因此+是下一个令牌。这留下了i
  • i可以是令牌,但i)不能,因此i是下一个令牌。

因此,表达式为i ++ ++ + i

然后语法规则将此表达式构造为((i ++) ++) + i

评估i++时,结果只是一个值,而不是左值。由于++无法应用于非左值的值,因此不允许使用(i ++) ++

在编译器识别出表达式在语义上不正确之后,它无法返回并更改词法分析。 Th C标准规定必须遵循规则,如上所述。

i+++i中,代码违反了单独的规则。这被解析为(i ++) + i。此表达式同时修改i(在i ++中)和单独访问它(在i的{​​{1}}中)。这违反了C 2011(1570)6.5 2:

  

如果对标量对象的副作用相对于同一标量对象的不同副作用或使用相同标量对象的值进行的值计算未被排序,则行为未定义。

此规则使用了一些技术术语:在+ i中,更改i ++的效果是i的副作用。 (主要作用是产生++的值。)ii的使用是标量对象+ i的值计算。这两件事情都没有排序,因为C标准没有规定在i中更改i之前或之后是否为+ i生成i的值。