i = i ++;未定义。 i = foo(i ++)也未定义吗?

时间:2015-06-26 01:11:54

标签: c++ undefined-behavior

例如:

int foo(int i) { return i; }

int main()
{
  int i = 0;

  i = i++;      // Undefined
  i = foo(i++); // ?

  return 0;
}

当前的ISO C ++标准对此案例的规定是什么?

修改

这是我感到困惑的地方:

  

除非另有说明,否则对单个操作符的操作数和单个表达式的子表达式的评估是不合理的。

     

如果对标量有副作用   对于相同标量对象的另一个副作用或值计算,对象未被排序   使用相同标量对象的值,并且它们不是潜在的并发(1.10),行为是   未定义。

     

在所有情况下,分配都在值之后排序   计算右和左操作数,并在赋值表达式的值计算之前

     

调用函数中的每个评估(包括其他函数调用)都没有特别说明   在执行被调用函数体之前或之后对序列进行测序是不确定的   关于被调用函数的执行。

所以看起来你可以在作业的左侧(仅i)进行值计算,右侧有副作用(从{{1}修改i })没有相互排序。

EDIT2

对于发现自己的人来说,我发现here有一个关于排序的非常好的解释。

2 个答案:

答案 0 :(得分:15)

你引用的最后一句话是"在执行被调用函数体之前或之后没有特别排序" 所以问题是增量和分配是"否则在"之前或之后特别排序。功能体。

1.9 [intro.execution] p15有答案:

  

调用函数时(无论函数是否为内联函数),每个值计算和副作用   与任何参数表达式相关联,或与指定被调用函数的后缀表达式相关联   在执行被调用函数体内的每个表达式或语句之前进行排序。 [注意:价值   与不同参数表达式相关的计算和副作用是无法排序的。 - 结束记录]

因此i的增量发生在函数体之前,而i的赋值发生在函数返回之后,所以它的定义非常明确。

在pre-C ++ 11术语中,函数调用在增量和赋值之间引入了一个序列点。

答案 1 :(得分:11)

i = foo(i++);很好,因为i++在调用foo()之前执行。制作i的副本,然后递增i,然后将副本传递给foo()。这与明确地这样做是相同的:

int tmp = i++;
i = foo(tmp);