Reputation: 71
Are these two lines of code equivalent?
P1->OUT &= ~(uint8_t)(1<<1);
P1->OUT &= (uint8_t)(~(1<<1));
Upvotes: 4
Views: 102
Reputation: 753585
TL;DR — No! (They are not always the same, and the result depends on the type of P1->OUT
.)
I'm assuming the normal case of 2's-complement arithmetic. If you suffer from sign-magnitude or 1's-complement arithmetic, you have to think quite a lot harder, but the conclusion is probably the same (not always the same).
Case 1:
(1<<1)
is an int
value (0x02
).(uint8_t)(1<<1)
converts to uint8_t
, but the value is still 0x02
.~(uint8_t)(1<<1)
converts the uint8_t
value to int
again (usual arithmetic conversions) and applies the bit-wise inversion operator ~
to the result.Assuming a 32-bit int
type, you get 0xFFFFFFFD
to &
with P1->OUT
:
P1->OUT &= 0xFFFFFFFD;
Case 2:
(1<<1)
is an int
value (0x02
).~(1<<1)
is an int
value — assuming 32-bit int
, the value is 0xFFFFFFFD
.(uint8_t)~(1<<1)
casts to uint8_t
, zeroing the bits in the more significant bytes.Assuming a 32-bit int
type, you get 0x000000FD
to &
with P1->OUT
:
P1->OUT &= 0x000000FD;
So, the value combined with P1->OUT
is different, but the effect depends also on the (unspecified) type of P1->OUT
. If it is uint8_t
, then there's no difference; if it is uint64_t
, there is potentially a massive difference, but it also depends on the value in P1->OUT
before the compound assignment is executed.
Upvotes: 3
Reputation: 133879
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.
Upvotes: 3