i++ && j++
is definitely not equivalent to ++i && ++j
.
Take the case where both are zero - the first results in:
0 && j++
yielding a 0 result (and because of short-circuiting, j won't even get incremented).
In the second case, you'll get
1 && 1
yielding a 1 result.
With that in mind, let's look at your examples (spaces, semicolons and newlines added for readability):
First up:
int i = -1; int j = -1; int k = 0; int l = 2; int m = i++ && j++ && k++ || l++;
Let's first parenthesize completely to make it easier to deal with:
int m = ((i++ && j++) && k++) || l++;
So, what's going to happen? First, the
i++
.i
is incremented (and becomes0
), but because it's a post-increment, the expression's result is-1
. That gives:int m = ((-1 && j++) && k++) || l++;
Since the left side of that
&&
is non-zero, the right side is evaluated.j++
incrementsj
to0
, but again, post-increment means the expression's value is-1
.int m = ((-1 && -1) && k++) || l++;
Resolve that
&&
:int m = (1 && k++) || l++;
Next, the right side of the remaining
&&
.k
is incremented, becoming1
, but the expression yields0
:int m = (1 && 0) || l++;
Resolve this
&&
:int m = 0 || l++;
And finally, because the left side of the
||
is 0, the right side is evaluted.l
is incremented, becoming3
, but as a post-increment, yields2
:int m = 0 || 3;
Finally:
int m = 1;
And along the way we ended up with:
i = 0; j = 0; k = 1; l = 3;
Explaining your first printout.
Next, let's look at the second example (more condensed; let me know if you want more details):
int i = -1, j = -1, k = 0, l = 2, m; m = ((++i && ++j) && ++k) || ++l; // parenthesized for readability ^ // i is pre-incremented m = (( 0 && ++j) && ++k) || ++l; ^ // first && operator short-circuits m = (0 && ++k) || ++l; ^ // second && operator short-circuits m = 0 || ++l; ^ // l is pre-incremented m = 0 || 3; ^ // evaluate || operator m = 1;
The results are:
i = 0 j = -1 k = 0 l = 3 m = 1
Exactly what you saw printed out.