๐Ÿ”ข 19. Bitwise Programming

19.1 What Is Bitwise Programming?

Bitwise programming works directly with the individual bits of an integer. Each bit is either 0 or 1.

Decimal value โ†’ Binary representation โ†’ Individual bits โ†’ Bitwise operation โ†’ Result

Flags and masks let a program store and change several yes/no settings in one integer. Bitwise operations are also useful when interpreting binary data and working with device interfaces.

Think of it this way: write a small number in binary first. Apply the operator to each pair of bits, then convert the result back to decimal.

19.2 Binary Representation โ€” The Foundation

For an 8-bit unsigned value, each position represents a power of 2:

Bit76543210
Weight1286432168421

For example, 10 is 00001010 because 8 + 2 = 10.

19.3 The Bitwise Operators

OperatorNameWorks onMain idea
&ANDEach pair of bits1 only when both bits are 1
|OREach pair of bits1 when at least one bit is 1
^XOREach pair of bits1 when the bits are different
~NOTEach bitFlips every bit
<<Left shiftBits of a valueMoves bits toward higher positions
>>Right shiftBits of a valueMoves bits toward lower positions

19.4 Bitwise AND &

AND examines corresponding bits and produces 1 only when both input bits are 1.

12 = 1100
10 = 1010
     ----
&    1000 = 8

So 12 & 10 produces 8.

19.5 AND Truth Table

ABA & B
000
010
100
111
Common use: AND with a mask to test or clear selected bits.

19.6 Bitwise OR |

OR produces 1 when at least one corresponding bit is 1.

12 = 1100
10 = 1010
     ----
|    1110 = 14

So 12 | 10 produces 14.

19.7 Bitwise XOR ^

XOR produces 1 when the two corresponding bits are different.

12 = 1100
10 = 1010
     ----
^    0110 = 6

So 12 ^ 10 produces 6.

XOR memory rule: same โ†’ 0, different โ†’ 1.

19.8 XOR Truth Table

ABA ^ B
000
011
101
110

19.9 Bitwise NOT ~ โ€” Why Does ~5 Become -6?

The complement operator flips every bit of the promoted operand. A plain integer constant such as 5 has type int. On a twoโ€™s-complement system, flipping its bits gives the signed value -6:

 5  = 00000000 00000000 00000000 00000101
~5  = 11111111 11111111 11111111 11111010

The resulting bit pattern represents -6 in twoโ€™s complement.

For the usual twoโ€™s-complement signed representation:
~x = -x - 1

Therefore: ~5 = -5 - 1 = -6
Do not confuse: ~ is bitwise NOT; ! is logical NOT. They solve completely different problems.

19.10 Left Shift <<

A left shift moves bits toward higher positions and fills the lower positions with zeros. With unsigned arithmetic, bits that move beyond the valueโ€™s width are lost.

5       = 00000101
5 << 1  = 00001010 = 10
5 << 2  = 00010100 = 20

For nonnegative values, a left shift by n often corresponds to multiplying by 2^n when the result stays in range and the shift count is valid. Do not rely on this shortcut for every signed value.

19.11 Right Shift >>

A right shift moves bits toward lower positions. Bits shifted out on the right are discarded.

20      = 00010100
20 >> 1 = 00001010 = 10
20 >> 2 = 00000101 = 5

Unsigned right shift fills the left with zeros. In C17, right-shifting a negative signed value is implementation-defined. Use unsigned operands for the mask operations in this lesson.

19.12 Important Shift Rules

  • The right operand must be nonnegative.
  • Its value must be less than the width in bits of the promoted left operand.
  • Do not assume signed shifts behave like mathematical multiplication or division for every value.
  • Use unsigned integers when implementing masks and bit fields that require predictable binary behavior.
Placement rule: check the promoted left-operand type and a valid count before shifting. Using 1u for a mask avoids the sign bit issues that a plain signed 1 can introduce.

19.13 Check Odd or Even Using Bitwise AND

The least significant bit tells whether a nonnegative integer is odd or even.

number & 1
  • Result 0 โ†’ even
  • Result 1 โ†’ odd
10 = 1010   โ†’ 10 & 1 = 0
11 = 1011   โ†’ 11 & 1 = 1

19.14 Check Whether a Bit Is Set

To test bit position k, create a value with only that bit set. First check that k is in the range supported by the mask type:

mask = 1u << k;
if (value & mask)
    /* bit k is set */

Bit positions start at 0 from the least significant bit.

19.15 Set a Bit

Setting a bit means forcing it to 1 without changing the other bits:

value = value | (1u << k);

OR is used because a 1 in the mask turns the selected bit on.

19.16 Clear a Bit

Clearing a bit means forcing it to 0:

value = value & ~(1u << k);

The one-bit mask selects the target position. Inverting it leaves a zero there and ones elsewhere. AND then clears only the selected bit.

19.17 Toggle a Bit

Toggle means 0 becomes 1 and 1 becomes 0:

value = value ^ (1u << k);

XOR is ideal because XOR with 1 flips a bit, while XOR with 0 leaves it unchanged.

19.18 Bit Mask โ€” The Central Bitwise Technique

A mask is a carefully chosen bit pattern used to select or modify specific positions.

1u << 3  โ†’ 00001000

A 1 in a mask marks a position of interest. The operator determines the action: AND tests selected positions, OR sets them, XOR toggles them, and AND with the inverted mask clears them.

Test
value & mask
Set
value | mask
Toggle
value ^ mask
Clear
value & ~mask

19.19 Count Set Bits

A set bit is a bit whose value is 1. The simple approach repeatedly checks the lowest bit and shifts the value:

count = 0;
while (value != 0) {
    count += value & 1u;
    value >>= 1;
}

For a positive unsigned value, this loop visits positions up to the highest set bit. It takes O(log n) iterations as the value n grows, or at most the fixed width of its integer type.

19.20 Efficient Set-Bit Counting

A classic technique removes the lowest set bit in each iteration:

while (value != 0) {
    value = value & (value - 1);
    count++;
}

Each iteration removes one set bit. If the value contains s set bits, the loop runs s times and takes O(s) time. For zero, the body does not run.

19.21 Check Whether a Number Is a Power of 2

For a positive unsigned integer, a power of two has exactly one set bit.

value != 0 && (value & (value - 1)) == 0
Why? For example, 8 is 1000 and 7 is 0111. Their AND is zero because no position contains 1 in both numbers. Include the positive-value check: zero also gives zero in the bit expression, but is not a power of two.

19.22 Clear the Lowest Set Bit

The expression below removes the lowest 1-bit:

value = value & (value - 1);

This is the same operation used by the efficient set-bit counting algorithm.

19.23 Isolate the Lowest Set Bit

To keep only the lowest set bit:

lowest = value & (~value + 1);

For unsigned integers, the more familiar equivalent is:

lowest = value & -value;

Use the technique deliberately and keep the signed/unsigned type rules in mind.

19.24 Swap Two Values Using XOR

XOR can swap two integer values without a third variable:

a ^= b;
b ^= a;
a ^= b;
Important: use this as a bitwise exercise, not a general improvement over a temporary variable. If both operands refer to the same object, the first XOR clears it to zero and the swap fails.

19.25 Find the Unique Element Using XOR

If every value occurs exactly twice except one value, XOR can isolate the unique value because:

  • x ^ x = 0
  • x ^ 0 = x
  • XOR is associative and commutative.
result = 0;
for (i = 0; i < n; i++)
    result ^= a[i];

19.26 Using Bits as Flags

One integer can store several independent yes/no states. Each bit represents one flag.

#define READ_FLAG   (1u << 0)
#define WRITE_FLAG  (1u << 1)
#define EXEC_FLAG   (1u << 2)

This technique can represent multiple Boolean settings compactly inside one value.

19.27 Set, Clear and Toggle a Flag

flags |= READ_FLAG;      /* set */
flags &= ~READ_FLAG;     /* clear */
flags ^= READ_FLAG;      /* toggle */

if (flags & READ_FLAG)   /* test */
    printf("Enabled");

This is one of the most practical real-world uses of bitwise programming.

19.28 Print a Binary Representation

To print an unsigned integer in binary, inspect each bit from the most significant position toward the least significant position.

for (int i = width - 1; i >= 0; i--)
    printf("%u", (value >> i) & 1u);

This lessonโ€™s fixed-width examples deliberately use uint32_t where available. In more general code, choose the number of value bits and validate each shift rather than assuming every unsigned int has 32 bits.

19.29 Bitwise vs Logical Operators

BitwiseLogical
&, |, ^, ~&&, ||, !
Works on bit patternsWorks with truth conditions
5 & 3 โ†’ 15 && 3 โ†’ 1
Usually does not mean โ€œtrue/falseโ€Produces a logical truth result
Common interview trap: & is not the same as &&, and | is not the same as ||.

19.30 Common Bitwise Mistakes

  • Confusing bitwise and logical operators.
  • Forgetting that bit positions normally start at 0.
  • Using a shift count that is invalid for the operand width.
  • Assuming signed right shift always behaves the same on every implementation.
  • Using signed values when unsigned masks would make the intent clearer.
  • Forgetting integer promotions when using small integer types such as unsigned char.
  • Writing masks with the wrong type or width.
  • Assuming ~x simply means โ€œmake x negativeโ€. It flips bits; the resulting value is then interpreted as an integer.
  • Using the XOR swap trick when both operands refer to the same object.

19.31 Important Operator Precedence

Use parentheses around a bitwise result before comparing it. For example, (n & mask) != 0 tests the selected bits; n & mask != 0 is grouped differently because != has higher precedence.

if ((flags & MASK) != 0) {
    /* selected bit is set */
}

Show the intended grouping even when you know the precedence table. This makes a mask operation easier to review and reduces accidental tests of the wrong value.

CodeBhavya Rule: Choose the mask, state what its 1 bits select, and then choose the operation. Trace one small binary example before combining several operations.

19.32 Unsigned Masks and Safe Shift Counts

The shift count must be nonnegative and less than the width of the promoted left operand. The example additionally restricts bit to 0 through 31 because the stored result is uint32_t. A count of 32 is invalid for a 32-bit promoted operand.

Complete C program:

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>

int main(void)
{
    uint32_t value = 0U;
    unsigned bit = 5;
    if (bit < 32)
        value |= UINT32_C(1) << bit;
    printf("Mask value: %" PRIu32 "\n", value);
    return 0;
}

Expected output:

Mask value: 32

Step-by-step explanation:

  1. UINT32_C(1) supplies the constant 1 with a type suitable for at least 32-bit integer work. It is used here with uint32_t, and the condition limits the selected bit to 0 through 31.
  2. Shifting by five positions yields the value 32.
  3. Bitwise OR sets that flag in value.
Remember: This example requires uint32_t support and deliberately uses 32 bit positions. Other unsigned types may have a different width. PRIu32, supplied by <inttypes.h>, gives the matching output format for uint32_t.

19.33 Quick Revision

๐Ÿ“Œ & โ†’ AND

๐Ÿ“Œ | โ†’ OR

๐Ÿ“Œ ^ โ†’ XOR

๐Ÿ“Œ ~ โ†’ NOT

๐Ÿ“Œ << โ†’ Left shift

๐Ÿ“Œ >> โ†’ Right shift

๐Ÿ“Œ n & 1 โ†’ Check least significant bit

๐Ÿ“Œ n | (1u << k) โ†’ Set bit

๐Ÿ“Œ n & ~(1u << k) โ†’ Clear bit

๐Ÿ“Œ n ^ (1u << k) โ†’ Toggle bit

๐Ÿ“Œ n & (n - 1) โ†’ Remove lowest set bit

๐Ÿ“Œ n != 0 && (n & (n - 1)) == 0 โ†’ Power-of-two test for an unsigned value
INTERACTIVE LEARNING

๐ŸŽฌ Bitwise Programming โ€” Bit Mask Flow

Follow how a mask is created, used to check a selected bit, and then used to set that bit.

PROGRAM TRACING

๐Ÿ”Ž Program Tracing โ€” Bitwise Programming

Trace mask creation, checking a bit, and setting the selected bit.

19.34 Quick MCQs

Select an answer first, then click Check Answer. A correct choice becomes green. If the answer is wrong, your choice becomes red and the correct option becomes green. The explanation appears below.

1. Which operator performs bitwise AND?
2. Which operator performs bitwise XOR?
3. Which operator flips bits?
4. What is 5 & 3?
5. What is 5 | 3?
6. What is 5 ^ 3?
7. Which operator performs left shift?
8. Which expression checks whether bit k is set?
9. Which expression sets bit k?
10. Which expression removes the lowest set bit?
PRACTICE

19.35 ๐ŸŽฏ Practice Problems

Practice AND, OR, XOR, NOT, shifts, bit masks, set-bit counting, powers of two, flags, and XOR-based array problems. Use ๐Ÿ’ป Solve It Yourself first, open Hint only when needed, and use Show Program after attempting the problem.

๐Ÿ“ˆ Bitwise Programming Practice Progress
Solved 0 / 20
Completed with Solution 0
Total Score 0 / 400
Completion 0%
A problem counts as Solved when all test cases pass without opening the full solution. Problems completed after viewing the official solution are tracked separately.
1. Bitwise AND of Two Integers

Problem 1: Find the result of bitwise AND for two unsigned integers.

Input: Two unsigned integers a and b.

Output: Print a & b.

2. Bitwise OR of Two Integers

Problem 2: Find the result of bitwise OR for two unsigned integers.

Input: Two unsigned integers a and b.

Output: Print a | b.

3. Bitwise XOR of Two Integers

Problem 3: Find the result of bitwise XOR for two unsigned integers.

Input: Two unsigned integers a and b.

Output: Print a ^ b.

4. Bitwise NOT of a 32-bit Integer

Problem 4: Find the bitwise NOT of a 32-bit unsigned integer.

Input: One uint32_t value.

Output: Print the 32-bit unsigned complement.

5. Left Shift by One Position

Problem 5: Perform a left shift by one position on a 32-bit unsigned integer.

Input: One uint32_t value whose result fits in 32 bits.

Output: Print n << 1.

6. Right Shift by Two Positions

Problem 6: Perform a right shift by two positions on an unsigned integer.

Input: One unsigned integer n.

Output: Print n >> 2.

7. Odd or Even Using Bitwise AND

Problem 7: Check whether an integer is odd or even using bitwise AND.

Input: One integer n.

Output: Print "Odd" or "Even".

8. Check Whether the kth Bit is Set

Problem 8: Check whether bit k is set in a 32-bit unsigned integer.

Input: n and k, where 0 <= k < 32.

Output: Print "Set" or "Not Set".

9. Set the kth Bit

Problem 9: Set bit k of a 32-bit unsigned integer.

Input: n and k, where 0 <= k < 32.

Output: Print the modified value.

10. Clear the kth Bit

Problem 10: Clear bit k of a 32-bit unsigned integer.

Input: n and k, where 0 <= k < 32.

Output: Print the modified value.

11. Toggle the kth Bit

Problem 11: Toggle bit k of a 32-bit unsigned integer.

Input: n and k, where 0 <= k < 32.

Output: Print the modified value.

12. Count Set Bits

Problem 12: Count the number of set bits in a 32-bit unsigned integer using repeated bit checks.

Input: One uint32_t value.

Output: Print the number of 1 bits.

13. Brian Kernighan Set-Bit Count

Problem 13: Count set bits using Brian Kernighan's algorithm.

Input: One uint32_t value.

Output: Print the number of set bits.

14. Check Whether a Number is a Power of 2

Problem 14: Check whether a positive unsigned integer is a power of 2.

Input: One unsigned integer n.

Output: Print "Power of 2" or "Not Power of 2".

15. Find the Unique Element

Problem 15: Find the unique element in an integer array where every other element appears exactly twice.

Input: n followed by n integers.

Output: Print the unique element.

16. Print Binary Representation

Problem 16: Print the 32-bit binary representation of an unsigned integer.

Input: One uint32_t value.

Output: Print exactly 32 bits from bit 31 down to bit 0.

17. Swap Two Integers Using XOR

Problem 17: Swap two unsigned integers using XOR without a temporary variable.

Input: Two unsigned integers a and b.

Output: Print the swapped values.

18. Set, Clear and Toggle a Selected Bit

Problem 18: Given n and k, print the results of setting, clearing, and toggling bit k.

Input: A uint32_t n and bit position k, where 0 <= k < 32.

Output: Print Set, Clear, and Toggle results on separate lines.

19. Permission System Using Bit Flags

Problem 19: Implement READ, WRITE, and EXECUTE permissions using bit flags. Start with no permissions, apply three requested operations, then print the final permissions.

Input: Three integers: readFlag writeFlag executeFlag, each 0 or 1.

Output: Print permissions in the form READ=Yes/No WRITE=Yes/No EXECUTE=Yes/No.

20. Find Two Unique Numbers

Problem 20: Given an array where every number appears twice except two numbers, find those two unique numbers using bitwise operations.

Input: n followed by n integers. Exactly two values occur once; all others occur twice.

Output: Print the two unique values in ascending order.

19.36 Key Takeaway

๐ŸŽฏ Remember:

AND (&) โ†’ Select bits

OR (|) โ†’ Set bits

XOR (^) โ†’ Toggle / find differences

NOT (~) โ†’ Flip bits

Left Shift (<<) โ†’ Move bits left

Right Shift (>>) โ†’ Move bits right

n & 1 โ†’ Check odd/even

n & (n - 1) โ†’ Remove lowest set bit

1u << k โ†’ Create a mask for bit k
INTERVIEW PREPARATION

๐ŸŽค Bitwise Programming โ€” Interview Questions

1. What is the difference between bitwise & and logical &&?
2. Why are unsigned integers often preferred for bit manipulation?
3. How do you check whether bit k is set?
4. How do you clear bit k without changing other bits?
5. Why does n & (n - 1) remove the lowest set bit?
6. How can XOR find one unique element when all others appear twice?
7. How do bit flags represent multiple permissions?
8. What shift mistake should be avoided?
PLACEMENT TIPS

๐Ÿ’ก Bitwise Programming โ€” Placement Tips

  • For bit-position problems, write the mask first: 1u << k. Then decide whether the task needs &, |, ^, or ~.
  • Prefer unsigned values when a problem is specifically about binary representation and bit manipulation.
  • Remember the three core mask formulas: set with |, clear with & ~mask, and toggle with ^.
  • For power-of-two questions, handle zero separately before using n & (n - 1).
  • XOR is especially useful when duplicate values occur in pairs because equal values cancel.
  • Be careful with operator precedence; add parentheses around bitwise expressions when combining them with comparisons or arithmetic.
EXTRA PRACTICE

โœ๏ธ Bitwise Programming โ€” Extra Practice Questions

  1. Find the position of the lowest set bit in a positive integer.
  2. Reverse all 32 bits of an unsigned integer.
  3. Check whether two integers have opposite signs using a bitwise expression.
  4. Generate every subset of a small array using bit masks.
  5. Find the missing number from 0 to n using XOR.
  6. Implement a compact feature-control system using eight independent bit flags.
โ† Previous Topic: Command Line Arguments Next Topic: Enumerations & typedef โ†’