C++ 移位运算符优先级奇怪

发布于 2024-07-24 16:30:39 字数 526 浏览 5 评论 0原文

考虑以下代码:

typedef vector<int> intVec;

intVec& operator<<(intVec& dst, const int i) {
    dst.push_back(i);
    return dst;
}
int intResult0() {
    return 23;
}
int intResult1() {
    return 42;
}

// main
intVec v;
v << intResult0() << intResult1();

奇怪的是,编译器生成代码,该代码评估 intResult1 BEFORE intResult0 (使用最新的 VC 和 gcc 进行测试) 。 为什么编译器要这样做? 通过这样做,各个值的评估和使用之间的时间(不必要地)增加了(?),即首先获取 42,但最后推送到向量。 C++ 标准是否规定了这一点?

Consider the following code:

typedef vector<int> intVec;

intVec& operator<<(intVec& dst, const int i) {
    dst.push_back(i);
    return dst;
}
int intResult0() {
    return 23;
}
int intResult1() {
    return 42;
}

// main
intVec v;
v << intResult0() << intResult1();

The weird thing is, that the compiler generates code, which evaluates intResult1 BEFORE intResult0 (tested with newest VC und gcc).
Why would the compiler do this? By doing so, the time between evaluation and usage of the respective values is (unnecessarily) increased(?), i.e. 42 is fetched first, but pushed last to the vector.
Does the C++ standard dictate this?

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

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

发布评论

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

评论(4

双手揣兜 2024-07-31 16:30:39

两个序列点之间的子表达式的求值顺序未定义。

上面的代码是语法糖:

v.operator<<(intResult0()).operator<<(intResult1());

编译器唯一的约束是它必须在调用方法之前评估所有参数并遵守优先级规则。 但只要遵循这些规则,每个实现都可以选择细节,因此这个顺序可能会在编译器之间发生变化。

在此示例中:

  • 因此,在 intResult2() 之前调用 intResult1() 是完全合法的。
  • 但是 intResult0() 必须在调用operator<<()(左)之前调用
  • ,而 intResult1() 必须在调用operator<<()(右)
  • 和operator<<()(左) 之前调用必须在运算符<<()(右)之前调用,

请参阅此处了解更多信息:
什么是C++ 程序员应该了解的所有常见未定义行为?

C++ 程序员应该了解哪些常见的未定义行为?

The order of evaluation of sub-expressions between two sequence point is undefined.

The above code is syntactic sugar for:

v.operator<<(intResult0()).operator<<(intResult1());

The only constraint the compiler has, is that it must evaluate all parameters before a method is called and obey the precedence rules. But as long as it follows these rules each implementation is allowed to choose the details and as such this order may change between compilers.

In this example:

  • So it is perfectly legal to call intResult1() before intResult2().
  • But intResult0() must be called before the call to operator<<() (left)
  • and intResult1() must be called before the call to operator<<() (right)
  • and operator<<() (left) must be called before operator<<() (right)

See here for more info:
What are all the common undefined behaviours that a C++ programmer should know about?

and

What are all the common undefined behaviours that a C++ programmer should know about?

假扮的天使 2024-07-31 16:30:39

根据 Stroustrup 第 6.2.2 节:

评估顺序
表达式中的子表达式是
未定义。

According to Stroustrup section 6.2.2:

The order of evaluation of
subexpressions within an expression is
undefined.

绻影浮沉 2024-07-31 16:30:39

这与优先级无关。

最后一条语句中没有序列点,因此编译器可以自由地按其喜欢的任何顺序计算子表达式,只要在组合子表达式时使用优先级即可。

请注意,优先级定义求值的整体顺序 - 它只是定义如何组合具有多个运算符的表达式的操作数。

例如,在以下表达式中:

a() * b() + c()

在某些时候,编译器需要先计算 (a() * b()),然后再添加 c() 的结果,但没有说明每个函数调用需要执行什么顺序。 编译器可以很容易地决定首先调用 c(),将结果压入堆栈,然后执行任何需要执行的操作来评估 (a() * b())< /code> 表达式(在这种情况下,它可能决定首先评估 b())。

优先级所起的唯一作用是不允许编译器将表达式计算为:

a() * (b() + c())

This has nothing to do with precedence.

There is no sequence point in that last statement, so the compiler is free to evaluate the sub-expressions in whatever order it likes as long as precedence is used when combining the sub-expressions.

Note that precedence does not define an overall order of evaluation - it just defines how the operands of an expression with several operators will be combined.

For example, in the following expression:

a() * b() + c()

at some point, the compiler would need to evaluate (a() * b()) before adding in the result of c(), but there's nothing that says what order each individual function call needs to be made. The compiler can quite easily decide to call c() first, push the result on a stack, then do whatever it needs to do to evaluate the (a() * b()) expression (in which case, it might decide to evaluate b() first).

The only role that precedence plays is that the compiler is not permitted to evaluate the expression as:

a() * (b() + c())
去了角落 2024-07-31 16:30:39

C++ 标准,5:4

除非另有说明,顺序
个别操作数的评估
的运算符和子表达式
个别表达和顺序
其中发生副作用的是
未指定

The C++ Standard, 5:4

Except where noted, the order of
evaluation of operands of individual
operators and subexpressions of
individual expressions, and the order
in which side effects take place, is
unspecified

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