短路和括号

foo*_*bar 8 c++ evaluation operators parentheses short-circuiting

在处理单个短路运算符时,如何对子表达式进行分组是否重要?

a && b && c && d
a && (b && (c && d))
(a && b) && (c && d)
((a && b) && c) && d
Run Code Online (Sandbox Code Playgroud)

以上表达式是否相同?

Oli*_*rth 5

是的,这些表达式都是等效的,包括它们的短路行为.

括号改变了&&评估各个s 的顺序.但是,由于&&始终是左关联的,因此始终按从左到右的顺序评估这些术语.因此,一旦发现某个术语为假,其余部分就可以跳过.


fre*_*low 5

证明三个子表达式的两个简化情况的等价性相对容易:

a && (b && c)  -->  a && bc   // bc is a shorthand for b && c
Run Code Online (Sandbox Code Playgroud)

在这里,a将首先进行评估.如果是假的,短路将阻止评估bc.如果是,bc则将进行评估,b && c即将进行评估.如果b为false,c则不会被评估.

(a && b) && c  -->  ab && c   // ab is a shorthand for a && b
Run Code Online (Sandbox Code Playgroud)

在这里,ab将首先进行评估.(a && b首先评估.如果a是假,短路将阻止评估b.否则,ab产量b.)如果ab为假,c则不会被评估.


现在,如果您更喜欢证据来证明,您可以查看以下C代码的汇编输出:

int a(), b(), c(), d();

void e()
{
    a() && b() && c() && d();
}

void f()
{
    a() && (b() && (c() && d()));
}

void g()
{
    (a() && b()) && (c() && d());
}

void h()
{
    ((a() && b()) && c()) && d();
}
Run Code Online (Sandbox Code Playgroud)

(我使用C代码而不是C++代码来防止名称损坏.)

生成的程序集e:

_e:
    // ... enter ...
    call    _a
    testl   %eax, %eax
    je  L1
    call    _b
    testl   %eax, %eax
    je  L1
    call    _c
    testl   %eax, %eax
    je  L1
    call    _d
    testl   %eax, %eax
    nop
L1:
    // ... leave ...
Run Code Online (Sandbox Code Playgroud)

生成的程序集f:

_f:
    // ... enter ...
    call    _a
    testl   %eax, %eax
    je  L4
    call    _b
    testl   %eax, %eax
    je  L4
    call    _c
    testl   %eax, %eax
    je  L4
    call    _d
    testl   %eax, %eax
    nop
L4:
    // ... leave ...
Run Code Online (Sandbox Code Playgroud)

生成的程序集g:

_g:
    // ... enter ...
    call    _a
    testl   %eax, %eax
    je  L7
    call    _b
    testl   %eax, %eax
    je  L7
    call    _c
    testl   %eax, %eax
    je  L7
    call    _d
    testl   %eax, %eax
    nop
L7:
    // ... leave ...
Run Code Online (Sandbox Code Playgroud)

生成的程序集h:

_h:
    // ... enter ...
    call    _a
    testl   %eax, %eax
    je  L10
    call    _b
    testl   %eax, %eax
    je  L10
    call    _c
    testl   %eax, %eax
    je  L10
    call    _d
    testl   %eax, %eax
    nop
L10:
    // ... leave ...
Run Code Online (Sandbox Code Playgroud)

如您所见,除标签外,生成的汇编代码完全相同.