算子优先与评价顺序

算子优先与评价顺序

术语“运算符优先”和“评估顺序”是编程中非常常用的术语,对于程序员来说非常重要。据我所知,这两个概念是紧密联系在一起的;在谈论表达时,一个概念离不开另一个概念。

让我们举一个简单的例子:

int a=1;  // Line 1a = a++ + ++a;  // Line 2printf("%d",a);  // Line 3

现在,很明显Line 2导致未定义的行为,因为C和C+中的序列点包括:

  1. 在计算&(逻辑和)、欧元(逻辑OR)和逗号运算符的左操作数和右操作数之间。例如,在表达式中*p++ != 0 && *q++ != 0,子表达式的所有副作用*p++ != 0在尝试访问之前已完成。q.

  2. 在计算三元“问号”运算符的第一个操作数和第二个或第三个操作数之间。例如,在表达式中a = (*p++) ? (*p++)  : 0之后有一个序列点。*p++,这意味着在执行第二个实例时,它已经增加了。

  3. 在一个完整表达式的结尾。此类别包括表达式语句(例如赋值)。a=b;)、返回语句、if、Switch、while或do-while语句的控制表达式以及for语句中的所有三个表达式。

  4. 在函数调用中输入函数之前。未指定计算参数的顺序,但此顺序点意味着在输入函数之前,它们的所有副作用都已完成。在表达中f(i++) + g(j++) + h(k++)f的原始值的参数调用。i,但是i在进入f..同样,jk在输入前更新gh分别。但是,它没有按哪个顺序指定。f()g()h()被执行,也不按哪个顺序执行ijk都是递增的。的价值jk在…的身体里f因此是没有定义的。3注意,函数调用f(a,b,c)的逗号运算符和计算顺序的使用。ab,和c没有具体说明。

  5. 在函数返回时,将返回值复制到调用上下文中。(这个序列点仅在C+标准中指定;它仅隐式地存在于C中。)

  6. 在初始化器的末尾;例如,在声明中计算5之后int a = 5;.

因此,通过第3点:

在一个完整表达式的结尾。此类别包括表达式语句(例如赋值a=b;)、返回语句、if、Switch、while或do-while语句的控制表达式,以及for语句中的所有三个表达式。

Line 2显然会导致行为不明。这说明了未定义行为紧密耦合序列点.

现在让我们再举一个例子:

int x=10,y=1,z=2; // Line 4int result = x<y<z; // Line 5

现在很明显Line 5将使变量result商店1.

现在表达x<y<z在……里面Line 5可将其评价为:

x<(y<z)(x<y)<z..在第一种情况下,result将是0在第二种情况下result将是1..但我们知道,当Operator PrecedenceEqual/Same - Associativity因此,被评估为(x<y)<z.

这就是我们所说的MSDN条款:

C算子的优先级和结合性影响表达式中操作数的分组和求值。只有当其他优先级较高或较低的运算符存在时,运算符的优先级才是有意义的。首先计算具有高优先级运算符的表达式。优先级也可以用“绑定”一词来描述。具有较高优先级的运算符据说具有更紧密的绑定。

现在,关于上面的文章:

它提到“先计算具有较高优先级运算符的表达式”。

这听起来可能不正确。但是,如果我们考虑到这一点的话,我认为这篇文章并没有说错什么。()也是运算符。x<y<z(x<y)<z..我的推理是,如果联想性不起作用,那么整个表达式的评估就会变得模棱两可,因为<不是序列点.

另外,我发现的另一个链接是这样的算子优先性与结合性:

此页面按优先级(从最高到最低)列出C运算符。它们的结合性指示在表达式中应用优先级相等的操作符的顺序。

以第二个例子为例int result=x<y<z,我们可以在这里看到这三个表达式,xyz因为,表达式的最简单形式是由单个文字常量或对象组成。因此,表达式的结果xyz会在那里r值,即1012分别。因此,现在我们可以解释x<y<z10<1<2.

现在,由于我们有两个表达式要计算,所以不起作用吗?10<11<2既然运算符的优先级是一样的,它们从左到右被评估。?

以最后一个例子作为我的论点:

int myval = ( printf("Operator\n"), printf("Precedence\n"), printf("vs\n"),printf("Order of Evaluation\n") );

在上面的示例中,由于comma运算符具有相同的优先级,则计算表达式。left-to-right的返回值printf()存储在myval.

在……里面SO/IEC 9899:201X在……下面J.1未指明的行为它提到

慕莱坞森
浏览 465回答 3
3回答

撒科打诨

优先级影响计算顺序的唯一方法是创建依赖关系;否则,两者是正交的。您已经仔细选择了一些琐碎的示例,在这些示例中,由优先级创建的依赖关系最终确实完全定义了计算顺序,但这通常不是真的。不要忘记,许多表达式有两种效果:它们产生值,也有副作用。这两种情况不需要一起发生,所以即使依赖关系强制执行特定的计算顺序,这也只是值的求值顺序;它对副作用没有影响。

哈士奇WWW

查看这一点的一个好方法是获取表达式树。如果你有一个表达式,让我们说x+y*z您可以将其重写为表达式树:应用优先级和关联规则:x&nbsp;+&nbsp;(&nbsp;y&nbsp;*&nbsp;z&nbsp;)在应用优先级和关联规则之后,您可以安全地忘记它们。以树的形式:&nbsp;&nbsp;x+ &nbsp;&nbsp;&nbsp;&nbsp;y&nbsp;&nbsp;* &nbsp;&nbsp;&nbsp;&nbsp;z现在这个表达式的叶子是x,&nbsp;y和z..这意味着你可以评估x,&nbsp;y和z按您想要的任何顺序,这也意味着您可以评估*和x任何顺序。既然这些表情没有副作用,你就不在乎了。但是,如果它们这样做了,排序可能会更改结果,而且由于排序可以是编译器决定的任何内容,所以您有一个问题。现在,序列点给这种混乱带来了一点秩序。他们有效地把这棵树切成几段。x + y * z, z = 10, x + y * z优先性和结合性之后x + ( y * z ) , z = 10, x + ( y * z)树:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;&nbsp;+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;y&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;z&nbsp;&nbsp;,&nbsp;------------ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;z&nbsp;&nbsp;&nbsp;&nbsp;= &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;10&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;,&nbsp;------------ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;&nbsp;+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;y&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;z树的顶部将在中间之前进行评估,中间部分在底部之前进行评估。
打开App,查看更多内容
随时随地看视频慕课网APP