C增量运算符

C增量运算符,c,short-circuiting,post-increment,C,Short Circuiting,Post Increment,我已经在代码块中编译了下面的代码,它显示了输出0…0。但是我认为它的输出应该是0…1,因为这里的“if”语句不是真的,所以“if”后面的语句不会被执行。然后j增加1(因为“if”语句中的j++),但我仍然是0。最后一个printf()应该是0…1 #include <stdio.h> int main() { int i =0,j=0; if(i && j++) printf("%d..%d\n",i++,j); printf

我已经在代码块中编译了下面的代码,它显示了输出0…0。但是我认为它的输出应该是0…1,因为这里的“if”语句不是真的,所以“if”后面的语句不会被执行。然后j增加1(因为“if”语句中的j++),但我仍然是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;
}
#包括
int main()
{
int i=0,j=0;
if(i&&j++)
printf(“%d..%d\n”,i++,j);
printf(“%d..%d”,i,j);
返回0;
}

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

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

因为
i
0
(falsy),没有理由执行
j++
。这叫短路


它在检查
if(a
时很有用,因为
i
0
(falsy),所以没有理由执行
j++
。这叫短路


它在检查
if(a

您将无法递增
j
。请看您的if声明:

if(i && j++)

仅当
i
j
均为真时,才执行if块。但是由于
i
已经为false,因此甚至不需要检查
j++
。它也被称为。

您将无法获得递增的
j
。请看您的if声明:

if(i && j++)

仅当
i
j
均为真时,才执行if块。但是由于
i
已经为false,因此甚至不需要检查
j++
。它也被称为。

在if条件中,对j的增量没有被应用的原因是因为表达式被短路了,也就是说,i从来都不是非零,因此,不需要计算第二个表达式。

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

使用按位and和
&
而不是使用逻辑and和
,只要
i
j
0
1
,它就不会短路,也不会以您想要的方式工作:

...
if(i & j++)
    printf("%d..%d\n",i++,j);
或者如果他们不是:

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

不要使用逻辑and和
&
,而是使用按位and和
&
,只要
i和
j和
0或
1
,它们就不会短路,也不会按您想要的方式工作:

...
if(i & j++)
    printf("%d..%d\n",i++,j);
或者如果他们不是:

if (!!i & !!(j++))
   ...
参见C11 6.5.13逻辑与运算符p4(我的重点)

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

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

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

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


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

由于第一个条件
i
和&
运算符的左侧)的求值已经返回false,因此没有执行
j++
表达式,因此第二个条件
j++
的求值是不正确的


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

由于第一个条件的评估
i
&&
运算符的左侧)已返回false,因此第二个条件
j++
不会被计算


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

正如您在本示例代码中看到的,来自源代码 第二,如果未执行:

    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
movli(%rip),%eax

testl%eax,%eax;正如您在本示例代码中看到的,来自您的源代码 第二,如果未执行:

    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
movli(%rip),%eax

testl%eax,%eax;正如您提到的,if语句为false则为true。 但我相信所使用的概念/逻辑是不恰当的,原因如下

在此之前,让我们了解&&(逻辑AND)运算符的工作原理。 If表示如果与其关联的两个操作数都为true,则只有结果为true。 注:1.对于编译器,这意味着如果任何一个操作数为false,编译器将不会进一步计算,即跳到下一个有效代码行。 编程时,2.0(零)状态为false

那么, 编译器首先搜索运算符,然后查找 与之相关的

因此,一旦编译器遇到“&&”,它就会将操作符的左侧视为 &&(逻辑AND)的关联性从左到右,并计算左侧操作数的值