【问题标题】:C + C++ = undefined behavior? [duplicate]C + C++ = 未定义的行为? [复制]
【发布时间】:2012-02-10 20:43:25
【问题描述】:

可能重复:
How do we explain the result of the expression (++x)+(++x)+(++x)?
Undefined Behavior and Sequence Points

我有问题,当代码

U = C + C++;

以不同的方式运行标准类型和我自己的类型。 我有一个示例http://ideone.com/4S1uA,其中我的 int 和我的类 Int 有不同的值,这应该代表真正的 Int 的工作方式。

是否有可能使我的类的行为方式与标准 int 的工作方式相同?这段代码有未定义的行为吗?

为什么它是 undefiend 行为? C++ 有一个操作优先级,所以应该首先评估 c++,因为它改变了 a 的值,所以作为第一个参数的添加应该传递 new a 的值,第二个是旧值。它适用于 Int 类,但不适用于标准 int。

【问题讨论】:

  • 是的,这是未定义的行为。我会让其他人参考标准等来创建答案。
  • 是的,它是 UB,因为不确定是先评估 C 还是 C++。

标签: c++ undefined-behavior


【解决方案1】:

这段代码有未定义的行为吗?

是的。就副作用而言,计算操作数的顺序是未定义的。

标准第 6.5(2) 节说:

如果标量对象的副作用相对于同一标量对象的不同副作用或使用相同标量的值的值计算是无序的 对象,行为未定义。如果有多个允许的排序 表达式的子表达式,如果这样一个未排序的一面,则行为未定义 效果发生在任何排序中。

由于int是一个标量类型,而且由于这里的副作用是无序的,所以行为是未定义的。

你应该这样写你的代码:

U = 2*C;
C++;

【讨论】:

  • 我无法想象需要构造c + c++ 的情况,但我对这段代码应该如何工作存在一些争论。但是C++有一个操作优先级,所以应该首先评估c++,因为它改变了a的值,所以作为第一个参数的加法应该是新的值,第二个是旧的值。但这不适用于内置类型。
  • 计算操作数的顺序未定义。
  • @Seagull:这不是运算符优先级的问题。是的,++ 操作发生在 + 操作之前(由于优先级),但这并不能告诉您何时为该 + 操作的左侧评估 C 的值。
  • c++ 必须在调用加法之前进行评估。由于我的类有两个通过引用传递的参数,因此它将使用新值和旧值,并且它的行为是定义的。但是对于内置类型,我们没有关于如何执行加法的信息,因此我们不知道首先评估哪个操作数。我说的对吗?
  • 不完全。编译器在评估 C + C++ 时必须做三件事。首先,它必须找到 C 的值,然后它必须找到 C++ 的值,然后将它们相加。问题是前两个步骤的 order 没有定义,无论类型如何。这个表达式是 - 从未定义过的,你只是对你的类型感到幸运。
【解决方案2】:

是的,这是未定义的行为。您不能在同样修改变量的语句中访问变量两次,因为未定义表达式“C”和表达式“C++”的求值顺序。

【讨论】:

    【解决方案3】:

    这里涉及的概念是sequence points 之一。引用维基百科文章的开场白:

    命令式编程中的序列点定义了计算机程序执行中的任何点,在该点处,可以保证先前评估的所有副作用都已执行,并且后续评估的副作用尚未执行。

    在 C 中,+ 运算符确实不创建一个序列点。因此没有定义副作用的顺序。但是,在 C++ 中,重载的 operator + 是一个函数调用,它确实创建了一个序列点。这会在副作用方面产生不同的行为。请注意,虽然未指定评估函数参数的顺序,但所有副作用都在函数进入之前完成。因此,如果C + C++ 涉及重载的+ 运算符,则C++ 副作用将在+ 函数执行之前应用于+ 的左参数。这与 int 值的情况不同,在右侧的副作用完成之前,可能会或可能不会评估左侧。

    【讨论】:

    • if C + C++ involves an overloaded + operator, then the C++ side effect will have been applied to the left argument of + before the + function executes 不,f(c, c++) 也是标量 c 的 UB。
    • @Cubbi - 我没有说必须定义行为。我说过,在+ 执行之前,++ 的副作用已经完成(与内置的+ 运算符不同,它不会创建序列点)。对于标量,显然参数评估的顺序(即 UB)决定了传递给函数的值。对于对象,重点是+ 看到的左参数保证包含++ 的效果。
    猜你喜欢
    • 1970-01-01
    • 2018-05-03
    • 2021-05-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-09
    • 1970-01-01
    相关资源
    最近更新 更多