【问题标题】:C Increment operatorsC 增量运算符
【发布时间】:2013-07-16 16:11:36
【问题描述】:

我已经在代码块中编译了下面的代码,它显示了输出 0...0 。但我认为它的输出应该是 0...1 因为“if”语句在这里不正确,所以“if”后面的语句不会被执行。然后 j 增加 1(因为“if”语句中的 j++)但是i 仍然为 0。所以,最后一个 printf() 应该给出 0...1。

#include <stdio.h>

int main()
{
    int i =0,j=0;
    if(i && j++)
        printf("%d..%d\n",i++,j);
    printf("%d...%d",i,j);
    return 0;
}

【问题讨论】:

    标签: c short-circuiting post-increment


    【解决方案1】:

    参见C11 6.5.13 逻辑与运算符p4(我的重点)

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

    您示例中的第一个操作数是i。它比较等于 0,因此第二个操作数 (j++) 不会被评估(执行)。因此,您后来的printf 显示j 仍然为0 是正确的。

    【讨论】:

      【解决方案2】:

      因为i0(假),所以没有理由执行j++。这叫短路。

      它在像if(a &lt; v.size() &amp;&amp; v[a] == 5) // do something这样的检查中很有用

      【讨论】:

        【解决方案3】:

        条件的第一部分 (i) 已经为假,因此不执行第二部分 (j++)。

        【讨论】:

          【解决方案4】:

          您不会增加j。看看你的 if 语句:

          if(i && j++)
          

          只有当 ij 都为真时才执行 if 块。但是由于i 已经是假的,所以甚至不需要检查j++。也叫Short-circuit evaluation

          【讨论】:

            【解决方案5】:

            没有应用 if 条件中 j 的增量的原因是因为该表达式被短路了——即 i 永远不会非零,因此不需要计算第二个表达式。

            【讨论】:

              【解决方案6】:

              不要使用逻辑和&amp;&amp;,而是使用按位和&amp;,只要ij01,它就不会短路并按照您想要的方式工作:

              ...
              if(i & j++)
                  printf("%d..%d\n",i++,j);
              

              或者如果他们不是:

              if (!!i & !!(j++))
                 ...
              

              【讨论】:

                【解决方案7】:

                j++ 表达式未执行,因为第一个条件 i&amp;&amp; 运算符的左侧)的评估已经返回 false,因此第二个条件 j++ 未评估。

                这是编译器进行的常见优化,通常称为短路条件评估,在某些编译器中您可以关闭此优化,以避免这种副作用。

                【讨论】:

                  【解决方案8】:

                  正如您在此示例代码中看到的,来自您的源代码 第二个 IF 不执行:

                      movl    i(%rip), %eax       
                      testl   %eax, %eax          ; <-- if i
                      je  .L2
                      movl    j(%rip), %eax
                      testl   %eax, %eax          ; <-- if j Not EXECUTED !!!
                      setne   %dl 
                      addl    $1, %eax            ; <-- j++
                      movl    %eax, j(%rip)
                      testb   %dl, %dl
                      je  .L2
                      ...                         ; inner IF
                  .j2
                  

                  如另一个答案中所述。

                  【讨论】:

                    【解决方案9】:

                    正如您提到的,如果语句为假,则为真。 但我认为使用的概念/逻辑在某些地方不合适,原因会随之而来。

                    在此之前,让我们了解 &&(Logical AND) 运算符的工作原理。 If 声明如果与它关联的两个操作数都为真,则只有结果为真。 注意:1. 对于编译器,这意味着如果任何一个操作数为假,编译器将不会进一步计算,即跳到下一个有效的代码行。 2. 0(零)状态为假 - 在编程中。

                    嗯, 编译器首先搜索运算符,然后查找操作数 相关联。

                    所以,一旦编译器遇到'&&',它就会将运算符的左侧视为 &&(Logical AND) 的结合性是从左到右的,并计算左侧操作数的值为 0(零)。 现在,请参阅注释 2,然后参阅注释 1。

                    因此,编译器跳转到下一个有效语句,即 printf("%d...%d",i,j);

                    这里没有对变量“j”进行增量,因此“j”的值将保持为 0(零)。

                    注意:为了进一步明确这个想法,我建议尝试使用不同的 i 和 j 值的相同示例,例如 i=1 和 j=1 或 i=2 和 j=1。

                    【讨论】:

                      猜你喜欢
                      • 2011-02-16
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2012-10-17
                      • 1970-01-01
                      • 1970-01-01
                      • 2017-07-06
                      相关资源
                      最近更新 更多