Вы можете думать о x && y || z
как эквивалентном:
int func(int x, int y, int z) {
if (x) {
if (y) {
return true;
}
}
if (z) {
return true;
}
return false;
}
Поскольку оба значения x
и y
фиксируются как ненулевые значения, первый оператор возврата всегда выполняется.
На IA32 без оптимизации x && y || z
становится:
movl $1, 28(%esp) ; store 1 in x (on stack)
movl $2, 24(%esp) ; store 2 in y (on stack)
cmpl $0, 28(%esp) ; compare x to 0
je .L6 ; if x is 0 jump to L6
cmpl $0, 24(%esp) ; compare y to 0
jne .L7 ; if y is 0 jump to L7
.L6: ; We only get to L6 if (x && y) was false
cmpl $0, 20(%esp) ; compare z to 0
je .L8 ; if z is 0 jump to L8
.L7: ; We get to this label if either (x && y) was true
; or z was true
movl $1, %eax ; copy 1 into register eax, the result
jmp .L9 ; jump unconditionally to L9
.L8: ; We only get here if both (x && y) and z are false
movl $0, %eax ; copy 0 into register eax, the result
.L9:
И func
становится:
cmpl $0, 8(%ebp) ; compare first argument (x) with 0
je .L2 ; jump to L2 if it is
cmpl $0, 12(%ebp) ; compare second argument (y) with 0
je .L2 ; jump to L2 if it is
movl $1, %eax ; store 1 for the return value (via register eax)
jmp .L3 ; jump to L3 (done, return to caller)
.L2: ; if we hit this label both x and y were false
cmpl $0, 16(%ebp) ; compare third argument (z) with 0
je .L4 ; if it is 0 jump to L4
movl $1, %eax ; store 1 in register eax, which is the return value
jmp .L3 ; jump to L3 (return to caller)
.L4: ; if we get here x, y and z were all 0
movl $0, %eax ; store 0 in eax to return false
.L3:
При включенной оптимизации func()
выглядит еще больше как выражение(возвращаемое значение загружается только из одного места, хотя оно скрыто из-за x86), но выражение x && y || z
в основном исчезает, так как компилятор может определить его значение во время компиляции.