20

以下是测试代码:

int main()
{
    int a = 3;
    int b = 4;
    a = a + b - (b = a); 

    cout << "a :" << a << " " << "b :" << b << "\n";    
    return 0;
}

编译它会给出以下警告:

> $ g++ -Wall -o test test.cpp test.cpp: In function ‘int main()’:
> test.cpp:11:21: warning: operation on ‘b’ may be undefined
> [-Wsequence-point]

为什么操作可以是未定义的?

根据我的理解,首先(b = a)应该评估子表达式,因为()的优先级更高,因此设置b = a。然后,由于 '+' 和 '-' 具有相同的优先级,表达式将被左关联评估。因此,a + b接下来应该评估,最后(b = a)应该从 中减去的结果a + b。我看不到这里违反了任何序列点规则。

4

4 回答 4

20

正在评估的表达式和完成其副作用之间存在差异。

由于b = a括号的优先级更高,赋值表达式将在减法之前计算。它将提供 的值a作为评估的结果。但是,将该值写入b可能要到下一个序列点才能完成,在这种情况下,下一个序列点是完整表达式的结尾。因此,整个表达式的最终结果是未定义的,因为减法可能会取b赋值之前或之后的值。

于 2012-11-09T23:50:58.617 回答
8

在 C++ 中,算术表达式中的子表达式没有时间顺序。

a = x + y;

x先评估,还是y?编译器可以选择其中一个,也可以选择完全不同的东西。求值顺序与运算符优先级不同:运算符优先级是严格定义的,而求值顺序仅定义为您的程序具有序列点的粒度。

事实上,在某些架构上,可以发出同时评估两者的代码x——y例如,VLIW 架构。

于 2012-11-09T23:50:30.583 回答
-1

为了解决它,将它们分成两个不同的语句。

PS:不要忘记人类在执行算术运算时可能会出错。因此,最好通过将它们分开在不同的语句中来使操作更清晰。我希望我有所帮助。

int main() 
{
   int a = 3;
   int b = 4;

   /* Two different Statements*/
   b = a;

   /* or a = a + b - a */
   a = a + b - b; 

   cout<<"a :"<<a<<" "<<"b :"<<b<<"\n";    
   return 0;
}
于 2012-11-09T23:57:13.987 回答
-1

a = b + a - a; 只是写成

a = b + a - (b = a)------>> (exp 1)

以下三个结果与(exp 1)相同 a = (b + a - (b = a)); a = ((b + a) - (b = a)); a = (b + a) - (b = a);

观察 +, - 运算符具有相同的优先级,并且具有从左到右的关联性因此首先执行“b+a”,然后在减法之前将“a”值分配给“b”

现在观察以下当 a = 10 和 b = 20 时;

a = (b = a) - b + a; =======> a = 10; b = 10 a = ((b = a) - b + a); =======> a = 10; b = 10

a = ((b = a) - (b + a));=======> a = -10; b = 10 从上面的表达式可以清楚地看出,即使最里面的括号首先被执行,也会首先遵循关联性,然后是优先级

注意:为避免混淆外括号和内括号的优先级考虑以下表达式 a = (b + a - (b = a))=====> 实际结果 => a = 20, b = 10; 本来是 a = 10, b = 10; (如果与关联性相比,优先级是主要的)因此,通过上面的示例,我们可以说与优先级相比,关联性是主要的

于 2016-09-07T05:11:25.230 回答