表达式求值的顺序

发布于 2024-12-07 12:36:55 字数 222 浏览 3 评论 0原文

我刚刚读到 C++ 中运算符的求值顺序和优先级是不同但相关的概念。但我仍然不清楚它们有何不同但又有何关联?

int x = c + a * b;    // 31
int y = (c + a) * b;  // 36

上述陈述与评估顺序有什么关系?例如,当我说 (c + a) 时,我是否通过更改表达式的优先级来更改表达式的求值顺序?

I've just read that order of evaluation and precedence of operators are different but related concepts in C++. But I'm still unclear how those are different but related?.

int x = c + a * b;    // 31
int y = (c + a) * b;  // 36

What does the above statements has to with order of evaluation. e.g. when I say (c + a) am I changing the order of evaluation of expression by changing its precedence?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

北城半夏 2024-12-14 12:36:55

关于评估顺序的重要部分是任何组件是否有副作用。

假设你有这样的情况:

int i = c() + a() * b();

其中 ab 有副作用:

int global = 1;

int a() {
    return global++;
}
int b() {
    return ++global;
}
int c() {
    return global * 2;
}

编译器可以选择调用 a(), b 的顺序()c(),然后将结果插入到表达式中。此时,优先级将接管并决定应用 +* 运算符的顺序。

在此示例中,最可能的结果是

  1. 编译器将首先计算 c(),然后是 a(),然后是 b(),导致 i = 2 + 1 * 3 = 5
  2. 编译器将首先计算 b(),然后是 a(),然后是 c(),导致 i = 6 + 2 * 2 = 10

但是编译器可以自由选择它想要的任何顺序。

简而言之,优先级告诉您运算符应用于参数的顺序(*+ 之前),而 顺序求值告诉您解析参数的顺序(a()b()c())。这就是为什么它们“不同但相关”。

The important part about order of evaluation is whether any of the components have side effects.

Suppose you have this:

int i = c() + a() * b();

Where a and b have side effects:

int global = 1;

int a() {
    return global++;
}
int b() {
    return ++global;
}
int c() {
    return global * 2;
}

The compiler can choose what order to call a(), b() and c() and then insert the results into the expression. At that point, precedence takes over and decides what order to apply the + and * operators.

In this example the most likely outcomes are either

  1. The compiler will evaluate c() first, followed by a() and then b(), resulting in i = 2 + 1 * 3 = 5
  2. The compiler will evaluate b() first, followed by a() and then c(), resulting in i = 6 + 2 * 2 = 10

But the compiler is free to choose whatever order it wants.

The short story is that precedence tells you the order in which operators are applied to arguments (* before +), whereas order of evaluation tells you in what order the arguments are resolved (a(), b(), c()). This is why they are "different but related".

流心雨 2024-12-14 12:36:55

“求值顺序”是指同一表达式内的不同子表达式相对于彼此求值的时间。

例如,

3 * f(x) + 2 * g(x, y)

乘法和加法之间有通常的优先规则。但我们有一个求值顺序问题:第一个乘法会在第二个乘法之前发生,还是第二个乘法会在第一个乘法之前发生?这很重要,因为如果 f() 具有改变 y 的副作用,则整个表达式的结果将根据运算顺序而有所不同。

您的特定示例中,不会出现这种评估场景的顺序(其中结果值取决于顺序)。

"Order of evaluation" refers to when different subexpressions within the same expression are evaulated relative to each other.

For example in

3 * f(x) + 2 * g(x, y)

you have the usual precedence rules between multiplication and addition. But we have an order of evaluation question: will the first multiplication happen before the second or the second before the first? It matters because if f() has a side effect that changes y, the result of the whole expression will be different depending on the order of operations.

In your specific example, this order of evaluation scenario (in which the resulting value depends on order) does not arise.

请远离我 2024-12-14 12:36:55

只要我们谈论内置运算符:不,您不会使用 () 更改计算顺序。您无法控制评估顺序。事实上,这里根本不存在“评估顺序”。

只要结果正确,编译器就可以以任何想要的方式计算该表达式。甚至不需要使用加法和乘法运算来计算这些表达式。加法和乘法仅存在于程序文本中。编译器可以完全忽略这些特定操作。在某些硬件平台上,此类表达式可能由单个原子机器操作求值。因此,“求值顺序”的概念在这里没有任何意义。那里没有任何东西可以应用“秩序”的概念。

使用 () 唯一改变的是表达式的数学含义。假设 abc 都是 2a + 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;

这也将产生正确的结果(假设没有与溢出相关的问题)。在这种情况下,实际的评估计划根本不会像您在源代码中编写的那样。

简而言之,假设实际的评估与您在程序源代码中编写的内容有任何显着的相似之处,这充其量是天真的。尽管人们普遍认为,内置运算符通常不会翻译成其机器“对应项”。

上述内容同样适用于内置运算符。一旦我们开始处理重载的运算符,事情就会发生巨大的变化。重载运算符确实完全按照表达式的语义结构进行计算。即使对于重载的运算符也有一定的自由度,但它并不像内置运算符那样不受限制。

As long as we are talking about built-in operators: no, you are not changing the order of evaluation by using the (). You have no control over the order of evaluation. In fact, there's no "order of evaluation" here at all.

The compiler is allowed to evaluate this expression in any way it desires, as long as the result is correct. It is not even required to use addition and multiplication operations to evaluate these expressions. The addition and multiplication only exist in the text of your program. The compiler is free to totally and completely ignore these specific operations. On some hardware platform, such expressions might be evaluated by a single atomic machine operation. For this reason, the notion of "order of evaluation" does not make any sense here. There's nothing there that you can apply the concept of "order" to.

The only thing you are changing by using () is the mathematical meaning of the expression. Let's say a, b and c are all 2. The a + b * c must evaluate to 6, while (a + b) * c must evaluate to to 8. That's it. This is the only thing that is guaranteed to you: that the results will be correct. How these results are obtained is totally unknown. The compiler might use absolutely anything, any method and any "order of evaluation" as long as the results are correct.

For another example, if you have two such expressions in your program following each other

int x = c + a * b;
int y = (c + a) * b;

the compiler is free to evaluate them as

int x = c + a * b;
int y = c * b + x - c;

which will also produce the correct result (assuming no overflow-related problems). In which case the actual evaluation schedule will not even remotely look like something that you wrote in your source code.

To put it short, to assume that the actual evaluation will have any significant resemblance to what you wrote in the source code of your program is naive at best. Despite popular belief, built-in operators are not generally translated in their machine "counterparts".

The above applies to built-in operators, again. Once we start dealing with overloaded operators, things change drastically. Overloaded operators are indeed evaluated in full accordance with the semantic structure of the expression. There's some freedom there even with overloaded operators, but it is not as unrestricted as in case of built-in operators.

记忆之渊 2024-12-14 12:36:55

答案是可能也可能不会。

a、b 和 c 的计算顺序取决于编译器对此公式的解释。

The answer is may or may not.

The evaluation order of a, b and c depends on the compiler's interpretation of this formula.

可是我不能没有你 2024-12-14 12:36:55

考虑下面的例子:

#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(++) 世界中真的是这样吗?查看程序的输出。

Consider the below example:

#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;
}

Here in terms of math as we know it, a and b are to be computed equally and must have the same result. But is that true in the C(++) world? See the program's output.

囚我心虐我身 2024-12-14 12:36:55

我想介绍关于这个问题的一个链接值得阅读。
规则 3 和 4 提到了序列点,这是另一个值得记住的概念。

I want to introduce a link worth reading with regard to this question.
The Rules 3 and 4 mention about sequence point, another concept worth remembering.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文