I came across this code in a project I have started working on. The original developer is no longer available, and I can\'t make any sense of it:
Your program invokes undefined behavior in C. You are modifying i
and j
more than one time between two sequence points.
In Java and JavaScript the behavior is well-defined, and you have to look at the precedence and associativity of the operators.
The original developer is no longer available, and I can't make any sense of it.
The original developer has deliberately left a torturous assignment question in the code.
This is exactly the same answer given by Daniel Fischer, but to clearly explain, I'll evaluate in steps corresponding to the evaluation order.
k = (j = (i = 0) + 2) + 1;
With parenthesis & operator precedence, is evaluated as:
i = 0;
j = i + 2; // j = 2
k = j + 1; // k = 3
return i|= j|= k|= (j+= i) - - (k+++k) - - (i =+j);
Expanding the "|=" operators, this is equivalent to:
return i = i | ( j = j | ( k = k | ( (j+= i) - - (k+++k) - - (i =+j) ) ) );
Left of "|" operator is always evaluated first and remembered, so substituting variable values into left side:
return i = 0 | ( j = 2 | ( k = 3 | ( (j+= i) - - (k+++k) - - (i =+j) ) ) );
Then evaluating right side of each "|" operator (with parenthesis, operator and left-to-right precedence):
(j+= i): pre-increments j = j + i; // j = 2 + 0 = 2
then expression evaluates to j // evaluates to 2
(k+++k): first evaluates k++ // sub-expression evaluates to 3,
// then post-increments k: k = 4
then evaluates (k++)+k // evaluates to 3+4 = 7
(i =+ j): "=+" is not an java operator!!
it is evaluated as "=" operator followed by unary "+" operator
expression evaluates to +j // evaluates to 2
k = 3 | ( (j+= i) - - (k+++k) - - (i =+j) )
= 3 | ( 2 - -7 - -2) = 3 | 11 = (2+1) | (8+2+1) = (8+2+1) = 11
j = 2 | k
= 2 | 11 = (2) | (8+2+1) = 8+2+1 = 11
i = 1 | j;
= 1 | 11 = (1) | (8+2+1) = 8+2+1 = 11
return i; // return 11
What is the
=+
operator?
That's two operators, one assignment operator, =
, and one unary plus, +
, which does nothing.
Did you typo and mean the compund assignment operator +=
?
What is the
+++
operator?
Also two operators, one post-increment, ++
, and one addition, +
, (per the maximal munch rule, the longest valid token is chosen, it would become one addition and two unary plus if the shortest valid token were chosen).
What is the
- -
operator?
Again two operators, one subtraction, and one unary minus (negation).
What is the
|=
operator?
A compound assignment, bitwise-oring [or, in the case of boolean
values, logical-oring] the left-hand-side value with the right-hand-side value and storing that in the left-hand-side variable.
a |= b;
is nearly equivalent to
a = a | b;
but the left-hand-side operand is evaluated only once, and the latter may need an explicit cast where the former doesn't.
k = (j = (i = 0) + 2) + 1;
return i|= j|= k|= (j+= i) - - (k+++k) - - (i =+j);
It produces a value of 11. How does this work?
The first line is equivalent to
i = 0;
j = i+2;
k = j+1;
The assignment (i = 0
for example) evaluates to the value stored (in i
here).
The next line is, with proper spacing, and implicit parentheses added
return i |= (j |= (k |= (((j += i) - (-(k++ + k))) - (-(i = +j)))));
i |= stuff_1
: i
is evaluated (0), stuff_1
is evaluated, the bitwise or is taken, and the result stored in i
. Since i
is originally 0, that is equivalent to i = stuff_1
.
j |= stuff_2
: j
is evaluated (2), stuff_2
is evaluated, the bitwise or is taken, and the result is stored in j
.
k |= stuff_3
: k
is evaluated (3), then stuff_3
, left-to-right.
(j += i)
adds i
to j
, stores the sum in j
and returns j
's new value.
Since i
is 0, j
doesn't change and the value is 2.(k++ + k)
takes the old value of k
(3), increments k
and adds k
's new value (4), resulting in 7. That value is negated, and the negated value (-7) subtracted from 2, resulting in 2 - (-7) = 9
.(i = +j)
stores the value of j
(2) in i
and the value of the expression is also 2. The value is negated (-2) and subtracted from the 9 we got from the previous operations, so stuff_3
evaluates to 11, with the side effects that
i
is now 2j
is now 2 (didn't actually change, since i
was 0 initially)k
is now 4k
(3) is bitwise or'ed with 11, resulting in 11, that is stored in k
, and 11 is the value of stuff_2
, which is k |= stuff_3
.the old value of j
(2) is bitwise or'ed with the value of stuff_2
(11), resulting in 11. The value is stored in j
, and the value of stuff_1
(j |= stuff_2
) is 11.
the old value of i
(0) is bitwise or'ed with the value of stuff_1
(11), the result sored in i
, and the value of i |= stuff_1
is 11. That value is then returned.
To me, the best answer is Mike Rylander's (in comment).
Replace it with
return 11;
and commit.
I mean, the code is not dependent on anything written before, so it produces 11 everytime. It is a complex computation that takes time for nothing and produces 11. So you just have to return 11. Do not keep the useless code of a developper who was obviously having fun on you. It reminds me of a former colleague, who set a bomb in the code (something that seldom crashes, but sometimes crashes indeed), just before resigning...
Note : There might be a case where it is not equivalent: if i, j, and k are visible outside your method and reused somewhere else. But it is highly unlikely.