Why does i|= j|= k|= (j+= i) - - (k+++k) - - (i =+j) == 11?

大城市里の小女人 提交于 2019-12-04 07:18:58

问题


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 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

      • the stored value of i is now 2
      • the stored value of j is now 2 (didn't actually change, since i was 0 initially)
      • the stored value of k is now 4
    • the old value of k (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.




回答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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!