Skip to main content
The << operator in C is the bitwise left shift operator. It operates on integral types by shifting the binary representation of the promoted left operand to the left by the number of bit positions specified by the right operand.
result = left_operand << right_operand;

Integer Promotion and Mechanics

Before the shift operation occurs, C applies integer promotions to both operands independently. Types smaller than int (such as char, short, or uint8_t) are promoted to int (or unsigned int if int cannot represent all values of the original type). The shift operation is performed strictly on the promoted type of the left operand. When a left shift is executed at the bit level:
  1. The bits of the promoted left operand are moved to the left.
  2. The vacated Least Significant Bits (LSB) are filled with zeros.
  3. The bits that are shifted beyond the bit-width of the promoted type (Most Significant Bits, or MSB) are discarded.
Because of integer promotion, bits are not discarded at the boundary of the original small data type, but rather at the boundary of the promoted type (typically 32 bits).
uint8_t a = 255;        // 0xFF
// 'a' is promoted to 'int' (typically 32-bit) before shifting.
// The result is of type 'int', so bits are NOT discarded at the 8-bit boundary.
int b = a << 1;         // Result: 510 (0x000001FE), not 254

Result Type

The type of the evaluated result is strictly the type of the promoted left operand. The type and value of the right operand have no effect on the type of the result.

Mathematical Equivalence

For an expression E1 << E2, the operation is mathematically equivalent to multiplying the promoted E1 by 2E22^{E2}, provided that the resulting value can be perfectly represented in the promoted type of E1 without overflow.

Undefined Behavior (UB)

The C standard imposes strict constraints on the << operator. Violating these constraints results in Undefined Behavior:
  1. Negative Shift Count: If the right operand (E2) is less than zero.
    int res = 5 << -1; // UB
    
  2. Oversized Shift Count: If the right operand (E2) is greater than or equal to the width (in bits) of the promoted left operand.
    int32_t val = 1;
    int32_t res = val << 32; // UB (shift count >= 32)
    
  3. Negative Left Operand (Signed): If the promoted left operand has a signed type and a negative value.
    int res = -5 << 2; // UB
    
  4. Signed Overflow: If the promoted left operand has a signed type and a non-negative value, but the mathematical result of E1×2E2E1 \times 2^{E2} cannot be represented in the promoted result type.
    int32_t val = 1073741824; // 2^30
    int32_t res = val << 2;   // UB (2^32 exceeds int32_t max)
    

Well-Defined Unsigned Overflow

If the promoted type of the left operand is unsigned, overflow is well-defined. The result is mathematically reduced modulo 2N2^N, where NN is the bit-width of the promoted left operand. Note: This wrap-around guarantee only applies if the promoted type is unsigned. If an unsigned type (like unsigned char or uint8_t) promotes to a signed int, overflowing that signed int during the shift remains Undefined Behavior.
Tired of Poor C Skills? Fix That With Deep Grasping!Learn More