In addition to the already posted answers and understanding what these operators do, it is equally important to understand how dangerous bitwise operators are.
You are using integer literals like
1, a literal which is of type (signed)
int. Signed operators are dangerous to use together with bitwise operators.
Many operators like
~ don't care about the type of the operands, they work on the raw binary level. But the shift operators can invoke various nasty forms of undefined behavior bugs, should you shift a signed operand. For example, the code
1 << 31 invokes undefined behavior, since it shifts data into the sign bits. Similarly, right shifts of signed variables have implementation-defined behavior if the operand is negative.
To make things worse, there are implicit integer promotions. Code such as this also invokes undefined behavior:
unsigned char byte = 1;
byte = ~byte << 1;
Because it is the same thing as
0xFFFF FFFE << 1. Anything can happen here, including a program crash.
Similarly, code such as this will behave unexpectedly:
uint8_t mask = 0xF0;
uint8_t data = 0x01;
if(data > ~mask)
puts("0x01 is larger than 0x0F");
What this means in practice is that things like the mentioned De Morgan's laws do not necessarily apply transparently to C code! Implicit type promotions and poorly-specified behavior can cause havoc.
The solution is to avoid signed types in embedded systems, and to write code as free from implicit promotions as possible.
More info: Implicit type promotion rules.