ProgrammingEmbedded C Engineer

How do bitwise operators (&, |, ^, ~, <<, >>) work in C? What are their specifics when working with types of different lengths and signs, and what common mistakes do developers make when using them?

Pass interviews with Hintsage AI assistant

Answer.

Bitwise operators manipulate individual bits of integer types:

  • & — bitwise AND
  • | — bitwise OR
  • ^ — bitwise XOR
  • ~ — bitwise NOT
  • << — left shift
  • >> — right shift

Specifics:

  • Operators only work with integer types (int, unsigned int, etc.).
  • Signed numbers (signed) when shifted right (>>) can result in either arithmetic or logical shifting — it depends on the compiler.
  • Shifting by an amount greater than the width of the variable results in undefined behavior.
  • For reliable operation, unsigned types are often chosen to avoid sign extension.

Example:

unsigned int flags = 0; flags |= 0x1; // Set the 0-th bit flags &= ~0x2; // Reset the 1-st bit if ((flags & 0x4) != 0) { /* ... */ } // Check the 2-nd bit

Trick Question.

What is the difference between the right shift operation (>>) for signed int and unsigned int types?

Common incorrect answer: It is thought that right shifting always inserts zeros on the left, regardless of sign.

Correct answer: For unsigned int, right shifting (>>) always inserts zeros. For signed int, either the sign is inserted (ones if the number is negative) or zeros — it depends on the compiler implementation (architecture and C standard rules).

Example:

signed int a = -8; unsigned int b = (unsigned int)a; printf("%d\n", a >> 1); printf("%u\n", b >> 1);

In the first case, the result depends on the compiler; in the second, it will always be a logical shift with zeros.

Examples of real mistakes due to ignorance of the subtleties of the topic.


Story

In the protocol processing code, signal flags were stored in a char type. The programmer applied a shift of 8 bits (flag << 8), which, due to overflow and type promotion rules, led to the loss of all data — result was always zero.


Story

Reading data from a network protocol (big-endian). Using bitwise operations to combine bytes was not accompanied by casting to unsigned, which sometimes led to unexpected negative values when reading a structure field.


Story

Using ~ (bitwise NOT) to reset bits in a value of type int (for example, ~0x80) was misinterpreted as 0x7F, but in reality, it resulted in the negative number -129, leading to errors in subsequent calculations and logical checks.