DDRB &= ~_BV(PB1);
With DDRB
being a volatile unsigned char *
(i.e. 8 bits wide) …
The question suggests the asker has some belief that the ~
operation is affected by DDRB
. It is not.
In C, expressions form a tree, in which the operands of each operation may themselves by subexpressions with further operands, which may be further subexpressions. Then the semantics of each subexpression are determined by the types of the operands in that subexpression. The context of the surrounding operators and operands is irrelevant (with a few exceptions, such as that expressions in sizeof
applied to an object are not evaluated).
For ~
, the C 2018 standard says in clause 6.5.3.3, paragraph 4:
… The integer promotions are performed on the operand, and the result has the promoted type…
This means the integer promotions are applied to the operand, _BV(PB1)
.
The integer promotions are specified in 6.3.1.1 2. For an object with rank less than or equal to int
or unsigned int
, it says:
… If an int
can represent all values of the original type (as restricted by the width, for a bit-field), the value is converted to an int
; otherwise, it is converted to an unsigned int
…
Thus, in a typical C implementation, if _BV(PB1)
is a char
or unsigned char
, it is converted to int
. If it is wider than an int
and an unsigned int
, it is left unchanged.
Then the ~
inverts all bits in the resulting value, whatever type it is. DDRB
is irrelevant to that.
Then the &=
must be performed. A &= B
behaves largely like A = A & B
except the lvalue A
is determined only once. For &
, 6.5.10 3 says the usual arithmetic conversions are performed.
The usual arithmetic conversions are specified in 6.3.1.8 1. The complete details are a bit complicated, involving considerations of floating-point, integer types, rank, and signedness. However, given that DDRB
is an unsigned char
, we can say the usual arithmetic conversions will convert it to the type resulting from the prior ~
operation. This will effectively extended the DDRB
value with 0 bits, which will then be ANDed with the result of ~
.
Finally, the assignment is performed. Assignment converts the value being assigned to the type of the destination operand. In this particular situation, that will not change the value, because the AND operation has already limited to value to what is representable in an unsigned char
. In general, assignment to unsigned char
would convert the value to unsigned char
by wrapping modulo 2N, where N is the number of bits in an unsigned char
. This is equivalent to removing the high bits, leaving only the low N bits.