'运算符优先级'和'求值顺序'这两个术语在编程中非常常见,对于程序员来说非常重要。就我所理解的而言,这两个概念紧密相连;在讨论表达式时,一个离不开另一个。
我们来看一个简单的例子:
int a=1; // Line 1
a = a++ + ++a; // Line 2
printf("%d",a); // Line 3
现在很明显,Line 2
会导致未定义行为,因为C和C ++中的序列点包括:
在逻辑运算符&& (逻辑与)、|| (逻辑或)和逗号运算符的左右操作数计算之间。例如,在表达式
*p++ !=0 && *q++ !=0
中,子表达式*p++ !=0
的所有副作用都在尝试访问q
之前完成。在三元"问号"运算符的第一个操作数计算和第二个或第三个操作数之间。例如,在表达式
a=(*p++)?(*p++):0
中,第一个*p++
之后有一个序列点,这意味着它已经被递增了,当执行第二个实例的时候。在完整表达式的结尾。此类别包括表达式语句(如赋值
a=b;
)、返回语句、if、switch、while或do-while语句的控制表达式以及for语句中的所有三个表达式。在进入函数调用之前。参数的计算顺序未指定,但是这个序列点意味着它们的所有副作用在进入函数之前都已完成。在表达式
f(i++) + g(j++) + h(k++)
中,f
以i
的原始值作为参数调用,但在进入f
体之前,i
已经递增。同样,j
和k
分别在进入g
和h
之前更新。但是,并未指定按照哪个顺序执行f()
、g()
、h()
,也未指定按照哪个顺序递增i
、j
、k
。因此,f
主体中j
和k
的值是未定义的。3请注意,函数调用f(a,b,c)
不是逗号运算符的使用,a
、b
和c
的计算顺序未指定。在函数返回后,在将返回值复制到调用上下文之后。(这个序列点仅在C++标准中指定;它只隐含地存在于C中。)
在初始化程序的结尾;例如,在声明
int a=5;
中评估5之后。
因此,按照第三点的标准:
在完整表达式的结尾处。该类别包括表达式语句(例如赋值a=b;)、返回语句、if、switch、while或do-while语句的控制表达式以及for语句中的所有三个表达式。
第2行
明显会导致未定义行为。这展示了未定义行为与序列点是如何紧密关联的。
现在让我们看另一个例子:
int x=10,y=1,z=2; // Line 4
int result = x<y<z; // Line 5
现在很明显,Line 5
将使变量result
存储1
。
现在在Line 5
中,表达式x<y<z
可以被计算为:
x<(y<z)
或者 (x<y)<z
。 在第一种情况下,result
的值将为0
,而在第二种情况下,result
将为1
。但是我们知道,当运算符优先级相同时-关联性发挥作用,因此评估为(x<y)<z
。
这是在这篇MSDN文章中所说的:
C运算符的优先级和关联性影响表达式中操作数的分组和计算。仅当存在具有更高或更低优先级的其他运算符时,运算符的优先级才有意义。具有更高优先级的运算符的表达式首先进行评估。优先权也可以用单词“绑定”来描述。优先级更高的运算符被称为具有更紧密绑定力。
现在,关于上面的文章:
它提到“具有更高优先级的运算符的表达式首先进行评估。”
这可能听起来不正确。但是,如果我们考虑()
也是一个运算符,则x<y<z
与(x<y)<z
相同。我的理解是,如果关联性不发挥作用,则整个表达式的计算将变得模糊,因为<
不是序列点。
此外,我发现另一个链接在运算符优先级和关联性方面说:
此页面按优先级(从最高到最低)列出C运算符。它们的关联性指示在表达式中等优先级的操作符以什么顺序应用。
因此,针对第二个示例int result=x<y<z
,我们可以看到总共有3个表达式,即x
,y
和z
。由于表达式的最简单形式包括单个文字常量或对象,因此表达式x
,y
和z
的结果将是其rvalues,即分别为10
,1
和2
。因此,现在我们可以将x<y<z
解释为10<1<2
。现在,由于我们有两个要评估的表达式,即
10<1
或1<2
,并且运算符的优先级相同,所以关联性是否起作用?答案是它们从左到右依次计算。采用上述最后一个示例作为我的论点:
int myval = ( printf("Operator\n"), printf("Precedence\n"), printf("vs\n"),
printf("Order of Evaluation\n") );
在上面的例子中,由于逗号
运算符具有相同的优先级,表达式从左到右求值,并将最后一个printf()
的返回值存储在myval
中。
在SO / IEC 9899:201x的J.1未指定行为中提到:
除了函数调用(),&&,||,?:和逗号运算符(6.5)指定的之外,子表达式的求值顺序以及副作用发生的顺序。
现在我想知道,是否说:评估顺序取决于运算符的优先级,留下未指定行为的情况。是错误的呢?
如果在我的问题中有任何错误,请指出并纠正。我发布这个问题的原因是受到MSDN文章的困惑。它是在错误中还是不是?
(x<y)<z
只是澄清了结合性/优先级。子表达式(x<y)
和z
可以以任意顺序进行评估。 - Erik