Search code examples
cbit-manipulationlanguage-lawyerbitwise-operatorsunsigned-integer

Does the position of this bit-wise operator change the behavior?


Are these two lines of code equivalent?

P1->OUT &= ~(uint8_t)(1<<1);

P1->OUT &= (uint8_t)(~(1<<1));

Solution

  • It depends on the type of P1->OUT, and the system. The result of 1 << 1 is of type int.

    I am considering the general case of int n; instead of 1 << 1

    In

    P1->OUT &= ~(uint8_t)(n);
    

    the operand will be widened to int again before the ~ (the integer promotion), and the ~ would be applied to an int. The result will have all the high-order bits 8...k set. If P1->OUT is 8 bits wide it is OK, but if it has more bits then the result is not what you'd expect.

    This one is even worse:

    P1->OUT &= (uint8_t)(~(n));
    

    The ~ operand will be applied again to an int and that would be converted to uint8_t. now if ~n is actually negative (has its sign bit set) - and in case of ~(1 << 1) it would be negative - it will be fine in two's-complement implementations but totally incorrect in 1's-complement and sign-and-magnitude implementations, because the bit representations would not be the same.


    The proper way to do bit twiddling is always use unsigned int or a wider two's complement number:

    P1->OUT &= ~(1U << n);
    

    or

    P1->OUT &= (~(1U << n)) & 0xFF;
    

    to avoid the arithmetic conversions and integer promotions ever producing signed numbers.