【问题标题】:Is it undefined behaviour when program execution depends on execution order?当程序执行取决于执行顺序时,它是未定义的行为吗?
【发布时间】:2016-01-02 19:16:55
【问题描述】:

在形式的表达式中

f( g(), h() );

未定义g()h() 的评估顺序。它只是指定一个必须在另一个之前发生。如果g()h() 都具有程序执行所依赖的可见副作用,这是未定义的行为吗?

【问题讨论】:

  • stackoverflow.com/a/621548/276949 - 它将为特定的编译器定义,但不可移植。
  • 不是预先定义的行为......但是在一次评估中可能会以这种方式进行评估,而下一次则是另一个订单。如果有特定订单的 UB,那么整个程序都有 UB,与您的实现是否曾经有该特定订单无关。
  • 它不是 UB,但不管你怎么称呼它——你的程序都坏了!
  • 示例:int x = 1; int f() { return 1 / x; } int g(int,int) { return --x; } int main() { g(g(0, 0), f()); }。该程序具有未定义的行为,即使您的特定实现可能永远不会在 f() 之前实际评估 g(0,0)

标签: c++ undefined-behavior operator-precedence side-effects


【解决方案1】:

“未定义的行为”有一个非常具体的技术含义:它意味着程序可以做什么实际上没有任何限制。它可能使计算机着火或侮辱用户。在这里,执行顺序是未指定 - 根据评估事物的顺序,有几个可能发生的选项。如果不了解编译器、优化器和执行环境的更多信息,您将无法准确预测它将是哪一个。

【讨论】:

  • ...但只要这些订单都没有导致 UB,一切都很好。
  • @Deduplicator 是的,当然。人们一直在编写类似上述代码的代码,只要函数不对全局状态进行残酷和不寻常的事情,就没有任何问题。
  • @OliverCharlesworth 如果两个函数的副作用可以在没有另一个的情况下发生,则不会。如果g() 写入文件gh() 写入文件h,而f(g(), h()) 读取文件gh,则首先写入哪个文件并不重要,但是这两个函数的副作用发生在f 开始之前确实很重要。
  • 在“C++ 编程语言”第 260 页的 Stroustrup 中写道:“参数表达式的顺序依赖是非常糟糕的风格并且具有未定义的行为。” - 他错了吗?
  • @luskan 我认为“依赖”某些东西意味着如果它不成立,事情就会严重破裂(换句话说,未定义的行为)。 OP 的内容仅仅是可见的副作用是否会改变。如果您不关心他们的订单,那么您就不必依赖他们 (IMO)。
【解决方案2】:

不,不是。术语未定义的行为表示程序中可能发生任何事情(包括崩溃)。这里的行为是不可预测的,这意味着可能会发生一件事或另一件事,您不能依赖评估的顺序。

最大的不同在于,在您的情况下,理论上您可以通过在每次调用后测试选择的顺序并采取相应的行动来让您的程序回到正轨。另一方面,一旦遇到未定义行为案例,你就完蛋了:它可以随时随地以任何方式咬你,直到程序结束。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-31
    • 2020-09-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多