【问题标题】:C and C++ operand resolution orderC 和 C++ 操作数解析顺序
【发布时间】:2016-03-10 09:26:10
【问题描述】:

很多时候我看到(有时写)类似于这个例子的代码:

int a=0, b=2;
if( a && (b=func())!=0 ) {
//...

问题是:标准是否保证这些陈述?

  1. b 将不会被触及(并保持价值 2
  2. func() 不会被调用

反之亦然,如果我们写if( func()!=0 && a ) - 是否会调用标准保证func()

我对定义这是合法的特定标准段落感兴趣。

UPD:我的错字,从 int a=1 更改为 int a=0

【问题讨论】:

  • 在这种情况下 func 将被保证调用,因为 a = 1
  • 为什么a为1时a && (b=func())!=0会短路?
  • 还要注意你不应该这样写代码;保持简单和“愚蠢”。
  • 对我来说,如果条件是a ||(b=func()) != 0,这个问题会更有意义,因为这实际上是短路评估的情况。
  • 我会说它比 @AugustKarlstrom 强一点 - 这确实是非常糟糕的代码,作者应该被解雇或给予'-F'等级。

标签: c++ c language-lawyer


【解决方案1】:

到确切的问题;

问题是:标准是否保证这些声明?

到更新的问题;给定a=0。如果a==0,那么是的,短路评估将启动,func() 不会被调用;第二个操作数不会被计算。

如果a=1(原来是这样),则相反; func() 将被调用 - a1 因此“真”,结果第二个操作数被评估(它是一个逻辑与),b 将改变。如果运算符是||(逻辑或),则短路评估将启动,func() 不会被调用。

反之亦然,如果我们写if( func()!=0 && a ) -- 是否会调用标准保证func()

是的,总是计算第一个操作数。


是的,C++ 保证短路评估;

§5.14 逻辑与运算符

1 && 运算符从左到右分组。操作数都根据上下文转换为 bool(第 4 条)。如果两个操作数都为真,则结果为真,否则为假。与& 不同,&& 保证从左到右的评估:如果第一个操作数为假,则不评估第二个操作数。

2 结果是一个布尔值。如果对第二个表达式求值,则与第一个表达式关联的每个值计算和副作用都会在与第二个表达式关联的每个值计算和副作用之前进行排序。

§5.15 逻辑或运算符

1 || 运算符从左到右分组。操作数都根据上下文转换为 bool(第 4 条)。如果其中一个操作数为真,则返回真,否则返回假。与| 不同,|| 保证从左到右的评估;此外,如果第一个操作数的计算结果为真,则不计算第二个操作数。

2 结果是一个布尔值。如果对第二个表达式求值,则与第一个表达式关联的每个值计算和副作用都会在与第二个表达式关联的每个值计算和副作用之前进行排序。


C对应的引号是;

§6.5.13 逻辑与运算符

4 与按位二进制& 运算符不同,&& 运算符保证从左到右的求值;如果计算第二个操作数,则在第一个和第二个操作数的计算之间存在一个序列点。如果第一个操作数比较等于 0,则不计算第二个操作数。

§6.5.14 逻辑或运算符

4 与按位的| 运算符不同,|| 运算符保证从左到右的求值;如果计算第二个操作数,则在第一个和第二个操作数的计算之间存在一个序列点。如果第一个操作数比较不等于 0,则不计算第二个操作数。

【讨论】:

  • 是的,这就是短路的工作原理-但问题中的两个陈述在这里不是完全错误的-给定a = 1
  • @artm。是的,鉴于问题中的值,func() 将首先被调用,反之亦然。
  • @artm。也不知道(给定问题中的数据),也许添加一个注释,这是因为问题中的数据而不是 && 运算符固有的东西。
  • 对不起我对第一个案例的不好,我的意思是a==0
  • @PSIAlt.如果a==0,那么是的,短路评估将启动,func() 不会被调用。
【解决方案2】:

来自 C-90 标准。

6.5.13 逻辑与运算符

....

4 与按位二进制 & 运算符不同,&& 运算符保证从左到右的求值; 在计算第一个操作数之后有一个序列点。如果第一个操作数 比较等于 0,不计算第二个操作数。

逻辑或运算符也是如此。

【讨论】:

    【解决方案3】:

    && 运算符要求两个操作数都为真。如果第一个操作数的计算结果为 false,则不会计算第二个操作数。但是因为 a 是 1,所以它被认为是真的并且第二个表达式(操作数)被计算。因此func() 被调用并将其结果分配给b,然后b 被测试为非零。

    【讨论】:

      【解决方案4】:

      该标准保证&&序列中的语句从左到右进行评估,并且一旦其中一个评估为假,则不会评估其右侧的语句。

      【讨论】:

        【解决方案5】:

        问题是:标准是否保证这些声明?

        b 不会被触及(并且保持值为 2)

        func() 不会被调用

        不,事实上在这种情况下他们都错了。因为它是运算符&&,所以在这种特殊情况下不能应用快捷逻辑。

        如果您将其更改为 ||,那么您的语句是正确的 - 只有第一个操作数(在这种情况下为 a = 1)的评估就足够了,其余的将被忽略。


        由于问题更改为a = 0,那么是的,这两个陈述都是正确且有保证的。

        【讨论】:

        • 不,它没有 - 这正是重点。如果第一个操作数的计算结果为 0,则不需要计算第二个操作数,因为表达式不能再计算为 true。
        • @tofro - 第一个操作数是 a,在问题中是 1 而不是 0 - 所以必须评估第二个操作数。
        • 我的评论指的是“逻辑运算符 && 需要评估所有操作数”这句话——这通常是不正确的,不应该这样说。
        • @tofro 啊,现在我明白了,我专注于这个特殊问题 - 同意并编辑 - 谢谢。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-01-21
        相关资源
        最近更新 更多