问题
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:
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?
What is the =+
operator?
What is the +++
operator?
What is the - -
operator?
What is the |=
operator?
回答1:
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 ini
. Sincei
is originally 0, that is equivalent toi = stuff_1
.j |= stuff_2
:j
is evaluated (2),stuff_2
is evaluated, the bitwise or is taken, and the result is stored inj
.k |= stuff_3
:k
is evaluated (3), thenstuff_3
, left-to-right.(j += i)
addsi
toj
, stores the sum inj
and returnsj
's new value. Sincei
is 0,j
doesn't change and the value is 2.(k++ + k)
takes the old value ofk
(3), incrementsk
and addsk
's new value (4), resulting in 7. That value is negated, and the negated value (-7) subtracted from 2, resulting in2 - (-7) = 9
.(i = +j)
stores the value ofj
(2) ini
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, sostuff_3
evaluates to 11, with the side effects that- the stored value of
i
is now 2 - the stored value of
j
is now 2 (didn't actually change, sincei
was 0 initially) - the stored value of
k
is now 4
- the stored value of
- the old value of
k
(3) is bitwise or'ed with 11, resulting in 11, that is stored ink
, and 11 is the value ofstuff_2
, which isk |= stuff_3
.
the old value of
j
(2) is bitwise or'ed with the value ofstuff_2
(11), resulting in 11. The value is stored inj
, and the value ofstuff_1
(j |= stuff_2
) is 11.the old value of
i
(0) is bitwise or'ed with the value ofstuff_1
(11), the result sored ini
, and the value ofi |= stuff_1
is 11. That value is then returned.
回答2:
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
回答3:
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.
回答4:
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.
来源:https://stackoverflow.com/questions/13519990/why-does-i-j-k-j-i-kk-i-j-11