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

后端 未结 4 1874
挽巷
挽巷 2020-12-22 14:33

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:



        
相关标签:
4条回答
  • 2020-12-22 15:15

    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.

    0 讨论(0)
  • 2020-12-22 15:24

    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
    
    0 讨论(0)
  • 2020-12-22 15:30

    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.

    0 讨论(0)
  • 2020-12-22 15:36

    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.

    0 讨论(0)
提交回复
热议问题