在c中计算的表达式中,括号内的赋值运算符是什么时候



所以我在quora文章中看到了这段代码,用来交换两个数字。

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

我试过了,效果很好。但既然b = a在括号中,b值不应该被赋予第一个值吗?整个事情应该变成CCD_ 2使a保持其值?

我尝试了a = b + (b = a);a = 5 b = 10,最后我得到了a=10。看这里,我想它被评估为a = a + a

为什么会出现这种异常现象?

这是未定义的行为,因为C99 draft standard中的6.5.2部分声明:

在前一个和下一个序列点之间,对象的存储值应通过表达式的评估最多修改一次。72)此外,应仅读取前一个值,以确定要存储的值

在这种情况下,我们正在修改b,并使用它的值来确定a的结果,该标准给出了以下未定义的示例:

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

至少在gcc中启动警告会提醒出现问题,使用-W -Wall我会收到以下警告:

warning: operation on ‘b’ may be undefined [-Wsequence-point]

优先级确定哪些操作数由哪些运算符链接。它没有确定评估顺序。

赋值运算符的优先级很低。因此,在没有括号的情况下,表达式

a = a + b - b = a

将解析为:

(a) = (a + b - b) = (a)

这将导致一个错误,因为(a+b-b)不是一个左值。因此,需要使用括号来将两个操作数ba与赋值运算符分组,如原始语句中所示:

a = a + b - (b = a)

但所有的括号都是分组,而不是评估的顺序。

你所能确定的是,无论何时评估(b = a)

  1. 整个表达式的值将是a的值
  2. 作为副作用,b将被分配a的值

然而,这种情况何时发生在编译器中是不可预测的。标准是明确的:在复杂表达式中,子表达式的求值顺序和副作用发生的顺序是未指定的,即依赖于编译器。该标准没有对评估子表达式的顺序提出任何要求。

更一般地说,在C中,如果在表达式的其他地方使用变量时修改该变量的值,则得到的结果将是未定义的,这意味着任何事情都可能发生。绝对不能依赖表达式a = a + b - (b = a),因为它既修改了b的值,又在表达式的其他位置使用了a + a - a0的值。

因此,该表达式同时唤起了未指定的行为(依赖于特定的求值顺序)和未定义的行为(在表达式的其他地方使用变量值时修改变量值)。仔细想想,这是一个令人印象深刻的壮举!

编辑:以上内容适用于C99。最新的标准C11,显式调用此行为未定义:"如果标量对象上的副作用相对于同一标量对象上不同的副作用或使用同一标量的值进行的值计算是未排序的,则行为是未定义的。如果一个表达式的子表达式有多个允许的顺序,则如果这种未排序的副作用发生在任何顺序中,则行为就是未定义的"。"(6.5.2)。标准草案免费提供。

正如注释中所述,这是未定义的行为。代码是从左到右直接读取的,而不是使用PEMDAS。

最新更新