【问题标题】:Sequencing in composite conditional expression复合条件表达式中的排序
【发布时间】:2014-04-02 13:07:07
【问题描述】:

以下示例中的if 语句来自我正在尝试再次构建的一个旧项目。很抱歉,这不是一个可验证的示例,因为它不会重现错误,它可以自行编译。

enum S { };

struct R {
    S type, state;
    double height;
};

int main ()
{
    int rows;
    S alive, rc;
    double h;
    R *r, *n;

    // BEGIN
    if ( (((r = n-1)   ->type & rc) && h > r->height) ||
         (((r = n+1)   ->type & rc) && h > r->height) ||
         (((r = n-rows)->type & rc) && h > r->height) ||
         (((r = n+rows)->type & rc) && h > r->height) )
    {
        n->state = alive;
    }
    // END
}

但是,在项目中,使用相同的编译(clang 3.3,除了包含路径之外没有其他选项),它给出了

warning: multiple unsequenced modifications to 'r' [-Wunsequenced]

(指向子表达式r = n - 1)。 if 语句(标记在BEGIN-END 之间)在项目中是相同的,只是变量的类型可能不同。这里定义的类型只是粗略的近似,但我认为它们与警告并不真正相关。我已经能够将表达式简化为

if( (r = n) || (r = n) ) //...

同时仍在项目中重现警告。

我的理解是,运算符&&||(未重载时)的第一个操作数求值后有一个序列点。所以我无法解释这个警告。

如果对表达式的形式有任何想法,无论类型如何,那都会有所帮助。

编辑

使用 Vaughn Cato 的 cmets,我也发现

if( ((r = n-1) ->type) || ((r = n+1) ->type) )

产生警告,而

if( bool((r = n-1) ->type) || bool((r = n+1) ->type) )

没有。 S 实际上是一个模仿枚举的类,并且有一个自定义的底层类。它重载了位运算符&|! 用于掩码,以及隐式转换运算符到底层类型,在特定情况下为size_t。我不知道这有多大帮助,但很抱歉没有从一开始就披露更完整的信息。

【问题讨论】:

  • 所涉及的类型是否可以有用户定义的运算符&&||?只有内置的操作符有顺序保证。
  • 只有operator& 被重载,但即使在没有& 的简化表达式中,警告仍然存在。此外,r,n 是指针,所以我认为我不能重载其他任何东西。
  • +1:这是一个很深的问题。我已将答案扔进戒指,但有兴趣等待更详细的回复。
  • 项目中r的类型也是原始指针吗?
  • 请注意,现在 安全点 的概念已被弃用,取而代之的是定义良好的标准多线程内存模型。

标签: c++ logical-operators sequence-points


【解决方案1】:

见 N3797 1.9/15

除非另有说明,否则单个运算符的操作数和单个表达式的子表达式的求值是无序的。

5.14/2:(&& 运算符)
5.15/2:(|| 运算符)

如果计算第二个表达式,则每个值计算和副作用都关联 第一个表达式在与第二个表达式相关的每个值计算和副作用之前排序。

对“副作用”的引用意味着r 的值已正确排序。

我的阅读是这个警告是不正确的。表达式的顺序正确(不包括此处未显示的代码的任何奇怪效果)。

【讨论】:

    【解决方案2】:

    这里有一个常见的混淆。仅仅因为 ||&& 是排序点,暗示运行时会按照您认为的顺序评估 r

    它可以评估r = n - 1r = n + 1 等。之前任何if 表达式都以它喜欢的任何顺序进行评估是无序的。

    这就是编译器警告向您突出显示的内容。

    顺便说一句,即使是声称具有更好定义顺序的语言(例如 Java)也会受到我在这里提请您注意的效果的影响!

    【讨论】:

    • 抱歉,我不太明白。除了序列点,还需要short-circuiting and evaluation order,对吧?
    • 是的,确实有但是运行时仍然可以尝试预先计算所有r = 赋值表达式。这个网站上有一些真正的专家能够详细回答这个问题:让我们看看我们得到了什么。
    • 您说运行时计算数量的顺序可能与语言指定的顺序不同?这很难理解......
    • 您对r 的分配可以在if 评估甚至开始之前计算。正如我在回答中所说,它们是无序的。
    猜你喜欢
    • 2023-02-07
    • 2017-03-28
    • 2017-02-05
    • 2013-04-20
    • 2021-09-13
    • 1970-01-01
    • 2023-03-07
    • 1970-01-01
    • 2018-05-31
    相关资源
    最近更新 更多