In C, << in C and >> move the bits of an integer left or right. You use them to set or extract flags, pack values, and scale unsigned values when the operation stays within the type’s range. The reliable starting point is an unsigned operand: shifting left can discard high bits, while shifting right discards low bits. Operand promotions, the type’s width, and the shift count determine whether the expression is well-defined.
How bit shifting works in C
Before C shifts, both operands undergo integer promotions. A uint8_t value usually becomes int before a shift, unless int cannot represent every value, in which case it becomes unsigned int. The result has the promoted left operand’s type, and the valid count range depends on that type’s width, not necessarily on the original storage type. A count must be nonnegative and less than that width.
A shift moves each retained bit by one position per count step. Bits leaving either end are discarded; the operator does not rotate them around. For example, with a uint32_t value of decimal 13, the low eight bits are 00001101. Shifting left by two gives 00110100, which is decimal 52. In a full 32-bit display, the pattern changes from …00001101 to …00110100.
Left shift: << in C for unsigned integers
For an unsigned value x, x << n has the mathematical value of x × 2n, reduced modulo one more than the type’s maximum value. This makes unsigned left shift predictable even when high bits fall off. For example, a 32-bit uint32_t value of 0xC0000000u shifted left by two produces 0x00000000u: the low 32 bits of 0x300000000.
Multiplication by a power of two is useful intuition, not a universal replacement for arithmetic. If you need the full product, ensure it fits before shifting; otherwise, use a wider type or deliberately accept the unsigned modulo result.
Right shift in C: binary and decimal examples
For an unsigned value x, x >> n gives the floor of x / 2n. The shift fills positions on the left with zero bits and drops low bits. Starting with decimal 52, whose low eight bits are 00110100, 52u >> 2 becomes 00001101, or decimal 13. This traces the division intuition for unsigned values.
Because discarded bits do not return, right shift is also useful for reading a packed field: shift the desired field into the low positions, then mask it with a bitwise AND.
Signed values, the >> in C operator, and invalid shift counts
Signed operands require more care. A nonnegative signed value can be right-shifted with the expected quotient by 2n, but right shifting a negative signed value is implementation-defined. Many implementations copy the sign bit, producing an arithmetic shift, but C does not guarantee that result on every implementation.
Left shifting a signed value is undefined if the left operand is negative or if the mathematical result cannot be represented. Thus, 1 << 31 is not a portable way to create the top bit of a 32-bit signed integer. Use an appropriate unsigned constant, such as 1u, and account for its width instead.
The count itself has strict limits. A negative count does not mean “shift right”; it produces undefined behavior. A count equal to or greater than the promoted left operand’s width is also undefined, even for unsigned values. Guard variable counts with a check such as n >= 0 && n < W, where W is the promoted type’s width, and choose an unsigned type when you need predictable bit manipulation.
