The operators |
, &
, and ~
act on individual bits in parallel. They can be used only on integer types. a | b
does an independent OR operation of each bit of a
with the corresponding bit of b
to generate that bit of the result.
The operators ||
, &&
, and !
act on each entire operand as a single true
/false
value. Any data type can be used that implicitly converts to bool
. Many data types, including float
implicitly convert to bool with an implied !=0
operation.
||
and &&
also “short circuit”. That means whenever the value of the result can be determined by just the first operand, the second is not evaluated. Example:
ptr && (*ptr==7)
If ptr
is zero, the result is false without any risk of seg faulting by dereferencing zero.
You could contrast that with (int)ptr & (*ptr)
. Ignoring the fact that this would be a bizarre operation to even want, if (int)ptr
were zero, the entire result would be zero, so a human might think you don’t need the second operand in that case. But the program will likely compute both anyway.