我刚才读到,运算符的评估顺序和优先顺序是不同的,但C ++中的相关概念。但我还不清楚这些是如何不同但相关的?
int x = c + a * b; // 31
int y = (c + a) * b; // 36
以上陈述与评估顺序有何关系。例如当我说(c + a)
时,我是通过更改其优先级来改变表达式的评估顺序吗?
答案 0 :(得分:8)
关于评估顺序的重要部分是任何组分是否有副作用。
假设你有这个:
int i = c() + a() * b();
a
和b
有副作用:
int global = 1;
int a() {
return global++;
}
int b() {
return ++global;
}
int c() {
return global * 2;
}
编译器可以选择调用a()
,b()
和c()
的顺序,然后将结果插入表达式中。此时,优先级将接管并决定应用+
和*
运算符的顺序。
在这个例子中,最可能的结果是
c()
,然后评估a()
,然后评估b()
,结果为i = 2 + 1 * 3 = 5
b()
,然后评估a()
,然后评估c()
,结果为i = 6 + 2 * 2 = 10
但是编译器可以自由选择它想要的任何顺序。
简短的故事是优先级告诉您运算符应用于参数的顺序(*
之前的+
),而评估顺序告诉您参数的解析顺序(a()
,b()
,c()
)。这就是为什么它们“不同但相关”。
答案 1 :(得分:3)
“评估顺序”是指同一表达式中的不同子表达式相对于彼此进行评估。
例如在
中3 * f(x) + 2 * g(x, y)
你在乘法和加法之间有通常的优先规则。但是我们有一个评估问题的顺序:第一次乘法会在第一次之前发生在第二次或第二次之前吗?这很重要,因为如果f()具有改变y的副作用,则整个表达式的结果将根据操作的顺序而不同。
在您的特定示例中,不会出现此评估方案的顺序(其中结果值取决于订单)。
答案 2 :(得分:1)
只要我们讨论内置运算符:不,您不会使用()
更改评估顺序。您无法控制评估顺序。事实上,这里根本就没有“评估顺序”。
只要结果正确,就允许编译器以任何方式评估该表达式。甚至不需要使用加法和乘法运算来评估这些表达式。加法和乘法仅存在于程序的文本中。编译器可以完全和完全忽略这些特定操作。在某些硬件平台上,可以通过单个原子机操作来评估这样的表达式。出于这个原因,“评价顺序”的概念在这里没有任何意义。没有什么可以将“秩序”的概念应用到。
使用()
进行更改的唯一方法是表达式的数学含义。假设a
,b
和c
都是2
。 a + b * c
必须评估为6
,而(a + b) * c
必须评估为8
。而已。这是唯一可以保证的:结果是正确的。如何获得这些结果是完全未知的。只要结果正确,编译器就可以使用绝对任何方法和任何“评估顺序”。
再举一个例子,如果你的程序中有两个这样的表达式,那么
int x = c + a * b;
int y = (c + a) * b;
编译器可以自由地将它们评估为
int x = c + a * b;
int y = c * b + x - c;
也会产生正确的结果(假设没有溢出相关的问题)。在这种情况下,实际的评估计划甚至看起来都不像您在源代码中编写的内容。
简而言之,假设实际评估与你在程序源代码中写的内容有任何重大的相似之处,那就是天真。尽管人们普遍认为,内置运算符通常不会在其机器“对应物”中翻译。
以上内容同样适用于内置运营商。一旦我们开始处理重载运算符,事情就会发生巨大变化。实际上,重载的运算符完全根据表达式的语义结构进行评估。即使有重载运算符,也存在一些自由,但它不像内置运算符那样不受限制。
答案 3 :(得分:0)
答案可能会也可能不会。
a,b和c的评估顺序取决于编译器对该公式的解释。
答案 4 :(得分:0)
考虑以下示例:
#include <limits.h>
#include <stdio.h>
int main(void)
{
double a = 1 + UINT_MAX + 1.0;
double b = 1 + 1.0 + UINT_MAX;
printf("a=%g\n", a);
printf("b=%g\n", b);
return 0;
}
在我们所知的数学方面,a和b应该被同等地计算,并且必须具有相同的结果。但是在C(++)世界中是真的吗?查看程序的输出。
答案 5 :(得分:0)
关于这个问题,我想介绍值得阅读的a link。
规则3和规则4提到了sequence point
,这是另一个值得记住的概念。