Given
int x=1,y=2,z;
Could you explain why the result for:
x && y || z
is 1?
开发者_JAVA百科x && y = 1
x && y || z = 1
x && y || z
is equivalent to
(x && y) || z
if x=1
and y=2
then x&&y
is 1 && 2
which is true && true
which is true
.
true || z
is always true
. z
isn't even evaluated
x && y || z
=> (x && y) || z
=> 1 || z
=> 1
(bool)1 = true
(bool)2 = true
Uninitialized int refers to data that was saved in memory, where it is placed on stack... and it rarely is 0x00000000
, and even if it was, true || false = true
.
The &&
operator has higher precedence than the ||
operator. See, e.g., this operators precedence table, numbers 13 and 14.
Your example evaluates as (x && y) || z
. Thanks to the short circuiting rule, z
is never evaluated because the result of x && y
is already true
.
You can think of x && y || z
as equivalent to:
int func(int x, int y, int z) {
if (x) {
if (y) {
return true;
}
}
if (z) {
return true;
}
return false;
}
Since both x
and y
are fixed to be non-zero values the first return statement is always hit.
On IA32, without optimisation x && y || z
becomes:
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:
And func
becomes:
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:
With optimizations enabled func()
looks even more like the expression (the return value only gets loaded from one place, although it's obscured by x86-isms), but the expression x && y || z
basically disappears since the compiler is able to deduce its value at compile time.
Because x && y
is evaluated as (x != 0) && (y != 0)
, which is equivalent with 1 && 1
resulting 1. And 1 || 0
is 1, no matter what y value is.
The && operator has higher precedence than the || operator
There are 2 components here:
- Precedence
- Short-circuitry
If it helps you remember, in terms of mathematical operators, || can be replaced with the plus sign "+", which consists of 2 bars and as && can be replaced with a "." and has the multiplication's precedence over the "+" :-)
In C++ and C, when a boolean expression is being evaluated and the result can logically be inferred from a certain term, the following terms do not get evaluated: false && (expr2) is false AND expr2 does not get evaluated. true || (expr3) is true AND expr3 does not get evaluated.
I hope this helps =)
精彩评论