To add to what mem said:
&& and || are a logical operators for AND and OR
& and | are a bitwise operators for AND and OR
mem explained the logical operators. They are used to compare logical operations - true and false states. For example:
if(a> 3 && b <= 88)
//The code here will execute if a is greater than 3 AND
// b is less than or equal to 88
Bitwise operators work at the bit level. Here's a quick tutorial on bitwise operators. There are 6 of them.
Let's start with these variables
uint8_t a = 0x3B //00111011;
uint8_t b = 0x96 //10010110;
We will start with AND, OR, XOR, and NOT. These operators compare each bit between two values.
AND (& in C):
AND compares each bit and returns 1 if the two bits are 1 (true) otherwise 0 (false).
c = a & b;
c's value will be 0x12 or in binary 00010010. That is where there is a 1 in each bit for both values.
OR (| in C)
OR will return a 1 if there is a 1 in either value at that bit.
c = a | b;
c's value will be 0xBF or in binary 10111111
XOR (^ in C - pronounced exclusive OR):
XOR will return a 1 if there is a 1 at that bit for either value but not both. For example, if bit position 5 for both values has a 1 then XOr returns a 0. But if only one has a 1 and the other has a 0 XOR returns a 1.
c = a^b;
c's value is 0xAD - binary 10101101
NOT(! in C)
This returns the compliment of a value. This mean where there was a 0 there will now be a 1 and visa versa.
c = ~a;
c's value will be 0xC4 - binary 11000100
Sometimes it is easier to visualize the values if they are above each other, like:
And then there are two shift operators - left shift and right shift. These shift the bits by the corresponding value - in otherwords move the bits over. << for left shift and >> for right shift.
c = a << 2; // left shift a by 2
d = b >> 4; // right shift b by 4
c's value is 0xEC - binary 11101100
d's value is 0x03 - binary 00001001