๐ข 19. Bitwise Programming
Do not rely on memory alone when an expression becomes complicated. Parentheses make the intended operation visible to both the compiler and the reader.
if ((flags & MASK) != 0) {
/* selected bit is set */
}
Bitwise expressions can become difficult to read when mixed with arithmetic, relational, and logical operators. Use parentheses when the intended grouping is important.
19.31 Important Operator Precedence
- 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
~xsimply 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.30 Common Bitwise Mistakes
& is not the same as &&, and | is not the same as ||.| Bitwise | Logical |
|---|---|
&, |, ^, ~ | &&, ||, ! |
| Works on bit patterns | Works with truth conditions |
5 & 3 โ 1 | 5 && 3 โ 1 |
| Usually does not mean โtrue/falseโ | Produces a logical truth result |
19.29 Bitwise vs Logical Operators
For portable code, choose the width from the actual unsigned type rather than hard-coding an assumption when possible.
for (int i = width - 1; i >= 0; i--)
printf("%u", (value >> i) & 1u);
To print an unsigned integer in binary, inspect each bit from the most significant position toward the least significant position.
19.28 Print a Binary Representation
This is one of the most practical real-world uses of bitwise programming.
flags |= READ_FLAG; /* set */
flags &= ~READ_FLAG; /* clear */
flags ^= READ_FLAG; /* toggle */
if (flags & READ_FLAG) /* test */
printf("Enabled");
19.27 Set, Clear and Toggle a Flag
This technique can represent multiple Boolean settings compactly inside one value.
#define READ_FLAG (1u << 0)
#define WRITE_FLAG (1u << 1)
#define EXEC_FLAG (1u << 2)
One integer can store several independent yes/no states. Each bit represents one flag.
19.26 Using Bits as Flags
result = 0;
for (i = 0; i < n; i++)
result ^= a[i];
x ^ x = 0x ^ 0 = x- XOR is associative and commutative.
If every value occurs exactly twice except one value, XOR can isolate the unique value because:
19.25 Find the Unique Element Using XOR
a ^= b;
b ^= a;
a ^= b;
XOR can swap two integer values without a third variable:
19.24 Swap Two Values Using XOR
Use the technique deliberately and keep the signed/unsigned type rules in mind.
lowest = value & -value;
For unsigned integers, the more familiar equivalent is:
lowest = value & (~value + 1);
To keep only the lowest set bit:
19.23 Isolate the Lowest Set Bit
This is the same operation used by the efficient set-bit counting algorithm.
value = value & (value - 1);
The expression below removes the lowest 1-bit:
19.22 Clear the Lowest Set Bit
value != 0 && (value & (value - 1)) == 0
For a positive unsigned integer, a power of two has exactly one set bit.
19.21 Check Whether a Number Is a Power of 2
Each iteration eliminates one 1-bit, so the loop runs once per set bit rather than once per bit position.
while (value != 0) {
value = value & (value - 1);
count++;
}
A classic technique removes the lowest set bit in each iteration:
19.20 Efficient Set-Bit Counting
This is easy to understand and demonstrates how binary positions can be processed one at a time.
count = 0;
while (value != 0) {
count += value & 1u;
value >>= 1;
}
A set bit is a bit whose value is 1. The simple approach repeatedly checks the lowest bit and shifts the value:
19.19 Count Set Bits
value & maskvalue | maskvalue ^ maskvalue & ~maskThink of the mask as a set of switches identifying exactly which bits an operation should affect.
1u << 3 โ 00001000
A mask is a carefully chosen bit pattern used to select or modify specific positions.
19.18 Bit Mask โ The Central Bitwise Technique
XOR is ideal because XOR with 1 flips a bit, while XOR with 0 leaves it unchanged.
value = value ^ (1u << k);
Toggle means 0 becomes 1 and 1 becomes 0:
19.17 Toggle a Bit
The mask is first inverted so every other position remains 1 while the selected position becomes 0.
value = value & ~(1u << k);
Clearing a bit means forcing it to 0:
19.16 Clear a Bit
OR is used because a 1 in the mask turns the selected bit on.
value = value | (1u << k);
Setting a bit means forcing it to 1 without changing the other bits:
19.15 Set a Bit
Bit positions start at 0 from the least significant bit.
mask = 1u << k;
if (value & mask)
/* bit k is set */
To test bit position k, build a mask with only that bit set:
19.14 Check Whether a Bit Is Set
10 = 1010 โ 10 & 1 = 0
11 = 1011 โ 11 & 1 = 1
- Result
0โ even - Result
1โ odd
number & 1
The least significant bit tells whether a nonnegative integer is odd or even.
19.13 Check Odd or Even Using Bitwise AND
- 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.
19.12 Important Shift Rules
For unsigned values, zero bits are shifted in from the left. For negative signed values, the result of right shift is implementation-defined, so use unsigned types when you need predictable bit manipulation.
20 = 00010100
20 >> 1 = 00001010 = 10
20 >> 2 = 00000101 = 5
A right shift moves bits toward lower positions. Bits shifted out on the right are discarded.
19.11 Right Shift >>
For nonnegative values, a left shift by n often corresponds to multiplying by 2^n, but shift expressions must still respect C's type and undefined-behavior rules.
5 = 00000101
5 << 1 = 00001010 = 10
5 << 2 = 00010100 = 20
A left shift moves bits toward higher positions and inserts zeros into the vacated low-order positions.
19.10 Left Shift <<
~ is bitwise NOT; ! is logical NOT. They solve completely different problems.~x = -x - 1Therefore:
~5 = -5 - 1 = -6The resulting bit pattern represents -6 in twoโs complement.
5 = 00000000 00000000 00000000 00000101
~5 = 11111111 11111111 11111111 11111010
NOT flips every bit. For a signed C integer, the result must also be interpreted using the representation of signed integers on the implementation. On the usual twoโs-complement representation:
19.9 Bitwise NOT ~ โ Why Does ~5 Become -6?
| A | B | A ^ B |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 0 |
19.8 XOR Truth Table
So 12 ^ 10 produces 6.
12 = 1100
10 = 1010
----
^ 0110 = 6
XOR produces 1 when the two corresponding bits are different.
19.7 Bitwise XOR ^
So 12 | 10 produces 14.
12 = 1100
10 = 1010
----
| 1110 = 14
OR produces 1 when at least one corresponding bit is 1.
19.6 Bitwise OR |
| A | B | A & B |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 0 |
| 1 | 0 | 0 |
| 1 | 1 | 1 |
19.5 AND Truth Table
So 12 & 10 produces 8.
12 = 1100
10 = 1010
----
& 1000 = 8
AND examines corresponding bits and produces 1 only when both input bits are 1.
19.4 Bitwise AND &
| Operator | Name | Works on | Main idea |
|---|---|---|---|
& | AND | Each pair of bits | 1 only when both bits are 1 |
| | OR | Each pair of bits | 1 when at least one bit is 1 |
^ | XOR | Each pair of bits | 1 when the bits are different |
~ | NOT | Each bit | Flips every bit |
<< | Left shift | Bits of a value | Moves bits toward higher positions |
>> | Right shift | Bits of a value | Moves bits toward lower positions |
19.3 The Bitwise Operators
For example, 10 is 00001010 because 8 + 2 = 10.
| Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|---|---|---|---|---|---|---|---|---|
| Weight | 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 |
For an 8-bit unsigned value, each position represents a power of 2:
19.2 Binary Representation โ The Foundation
Bitwise operations are especially useful when a program needs compact flags, masks, device control, binary protocols, permissions, or low-level data manipulation.
Bitwise programming works directly with the individual bits of an integer. Each bit is either 0 or 1.
19.1 What Is Bitwise Programming?
19.32 Quick Revision
๐ | โ 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 & (n - 1) == 0 โ Power-of-two test when n is positive
๐ฌ Bitwise Programming โ Bit Mask Flow
Follow how a mask is created, used to check a selected bit, and then used to set that bit.
๐ฌ Bit Mask Visualizer
Example: n = 10 โ binary 1010, with k = 0.
๐ Program Tracing โ Bitwise Programming
Trace mask creation, checking a bit, and setting the selected bit.
โ
19.33 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.
The single ampersand operator & performs bitwise AND on integer operands.
The ^ operator performs bitwise exclusive OR.
The unary ~ operator produces the bitwise complement.
5 is 0101 and 3 is 0011. Their bitwise AND is 0001, which is 1.
0101 | 0011 gives 0111, which is 7.
0101 ^ 0011 gives 0110, which is 6.
The << operator shifts bits toward more-significant positions.
A mask with only bit k set is ANDed with n. A non-zero result means bit k is set.
OR with a one-bit mask forces bit k to 1 while preserving other bits.
For non-zero n, n & (n - 1) clears the lowest set bit.
19.34 ๐ฏ 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.
Problem 1: Find the result of bitwise AND for two unsigned integers.
Input: Two unsigned integers a and b.
Output: Print a & b.
C Code Editor
Sample Input
Program Output
Run your program to see the output.
Test Cases
#include <stdio.h>
int main()
{
unsigned int a, b;
scanf("%u %u", &a, &b);
printf("%u", a & b);
return 0;
}
Problem 2: Find the result of bitwise OR for two unsigned integers.
Input: Two unsigned integers a and b.
Output: Print a | b.
C Code Editor
Sample Input
Program Output
Run your program to see the output.
Test Cases
#include <stdio.h>
int main()
{
unsigned int a, b;
scanf("%u %u", &a, &b);
printf("%u", a | b);
return 0;
}
Problem 3: Find the result of bitwise XOR for two unsigned integers.
Input: Two unsigned integers a and b.
Output: Print a ^ b.
C Code Editor
Sample Input
Program Output
Run your program to see the output.
Test Cases
#include <stdio.h>
int main()
{
unsigned int a, b;
scanf("%u %u", &a, &b);
printf("%u", a ^ b);
return 0;
}
Problem 4: Find the bitwise NOT of a 32-bit unsigned integer.
Input: One uint32_t value.
Output: Print the 32-bit unsigned complement.
C Code Editor
Sample Input
Program Output
Run your program to see the output.
Test Cases
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
int main()
{
uint32_t n;
scanf("%" SCNu32, &n);
printf("%" PRIu32, (uint32_t)~n);
return 0;
}
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.
C Code Editor
Sample Input
Program Output
Run your program to see the output.
Test Cases
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
int main()
{
uint32_t n;
scanf("%" SCNu32, &n);
printf("%" PRIu32, (uint32_t)(n << 1));
return 0;
}
Problem 6: Perform a right shift by two positions on an unsigned integer.
Input: One unsigned integer n.
Output: Print n >> 2.
C Code Editor
Sample Input
Program Output
Run your program to see the output.
Test Cases
#include <stdio.h>
int main()
{
unsigned int n;
scanf("%u", &n);
printf("%u", n >> 2);
return 0;
}
Problem 7: Check whether an integer is odd or even using bitwise AND.
Input: One integer n.
Output: Print "Odd" or "Even".
C Code Editor
Sample Input
Program Output
Run your program to see the output.
Test Cases
#include <stdio.h>
int main()
{
int n;
scanf("%d", &n);
printf("%s", ((unsigned int)n & 1u) ? "Odd" : "Even");
return 0;
}
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".
C Code Editor
Sample Input
Program Output
Run your program to see the output.
Test Cases
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
int main()
{
uint32_t n;
unsigned int k;
scanf("%" SCNu32 " %u", &n, &k);
uint32_t mask = UINT32_C(1) << k;
printf("%s", (n & mask) ? "Set" : "Not Set");
return 0;
}
Problem 9: Set bit k of a 32-bit unsigned integer.
Input: n and k, where 0 <= k < 32.
Output: Print the modified value.
C Code Editor
Sample Input
Program Output
Run your program to see the output.
Test Cases
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
int main()
{
uint32_t n;
unsigned int k;
scanf("%" SCNu32 " %u", &n, &k);
n |= UINT32_C(1) << k;
printf("%" PRIu32, n);
return 0;
}
Problem 10: Clear bit k of a 32-bit unsigned integer.
Input: n and k, where 0 <= k < 32.
Output: Print the modified value.
C Code Editor
Sample Input
Program Output
Run your program to see the output.
Test Cases
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
int main()
{
uint32_t n;
unsigned int k;
scanf("%" SCNu32 " %u", &n, &k);
n &= ~(UINT32_C(1) << k);
printf("%" PRIu32, n);
return 0;
}
Problem 11: Toggle bit k of a 32-bit unsigned integer.
Input: n and k, where 0 <= k < 32.
Output: Print the modified value.
C Code Editor
Sample Input
Program Output
Run your program to see the output.
Test Cases
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
int main()
{
uint32_t n;
unsigned int k;
scanf("%" SCNu32 " %u", &n, &k);
n ^= UINT32_C(1) << k;
printf("%" PRIu32, n);
return 0;
}
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.
C Code Editor
Sample Input
Program Output
Run your program to see the output.
Test Cases
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
int main()
{
uint32_t n;
unsigned int count = 0;
scanf("%" SCNu32, &n);
while (n != 0)
{
count += n & 1u;
n >>= 1;
}
printf("%u", count);
return 0;
}
Problem 13: Count set bits using Brian Kernighan's algorithm.
Input: One uint32_t value.
Output: Print the number of set bits.
C Code Editor
Sample Input
Program Output
Run your program to see the output.
Test Cases
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
int main()
{
uint32_t n;
unsigned int count = 0;
scanf("%" SCNu32, &n);
while (n != 0)
{
n &= n - 1;
count++;
}
printf("%u", count);
return 0;
}
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".
C Code Editor
Sample Input
Program Output
Run your program to see the output.
Test Cases
#include <stdio.h>
int main()
{
unsigned int n;
scanf("%u", &n);
printf("%s",
(n != 0u && (n & (n - 1u)) == 0u)
? "Power of 2"
: "Not Power of 2");
return 0;
}
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.
C Code Editor
Sample Input
Program Output
Run your program to see the output.
Test Cases
#include <stdio.h>
int main()
{
int n;
int result = 0;
scanf("%d", &n);
for (int i = 0; i < n; i++)
{
int value;
scanf("%d", &value);
result ^= value;
}
printf("%d", result);
return 0;
}
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.
C Code Editor
Sample Input
Program Output
Run your program to see the output.
Test Cases
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
int main()
{
uint32_t n;
scanf("%" SCNu32, &n);
for (int i = 31; i >= 0; i--)
putchar((n & (UINT32_C(1) << i)) ? '1' : '0');
return 0;
}
Problem 17: Swap two unsigned integers using XOR without a temporary variable.
Input: Two unsigned integers a and b.
Output: Print the swapped values.
C Code Editor
Sample Input
Program Output
Run your program to see the output.
Test Cases
#include <stdio.h>
int main()
{
unsigned int a, b;
scanf("%u %u", &a, &b);
a ^= b;
b ^= a;
a ^= b;
printf("%u %u", a, b);
return 0;
}
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.
C Code Editor
Sample Input
Program Output
Run your program to see the output.
Test Cases
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
int main()
{
uint32_t n;
unsigned int k;
scanf("%" SCNu32 " %u", &n, &k);
uint32_t mask = UINT32_C(1) << k;
printf("Set = %" PRIu32 "\n", n | mask);
printf("Clear = %" PRIu32 "\n", n & ~mask);
printf("Toggle = %" PRIu32, n ^ mask);
return 0;
}
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.
C Code Editor
Sample Input
Program Output
Run your program to see the output.
Test Cases
#include <stdio.h>
int main()
{
const unsigned int READ = 1u << 0;
const unsigned int WRITE = 1u << 1;
const unsigned int EXECUTE = 1u << 2;
unsigned int permissions = 0u;
int readFlag, writeFlag, executeFlag;
scanf("%d %d %d", &readFlag, &writeFlag, &executeFlag);
if (readFlag) permissions |= READ;
if (writeFlag) permissions |= WRITE;
if (executeFlag) permissions |= EXECUTE;
printf("READ=%s WRITE=%s EXECUTE=%s",
(permissions & READ) ? "Yes" : "No",
(permissions & WRITE) ? "Yes" : "No",
(permissions & EXECUTE) ? "Yes" : "No");
return 0;
}
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.
C Code Editor
Sample Input
Program Output
Run your program to see the output.
Test Cases
#include <stdio.h>
#include <stdlib.h>
int main()
{
int n;
scanf("%d", &n);
unsigned int *a = malloc((size_t)n * sizeof *a);
if (a == NULL)
return 1;
unsigned int x = 0u;
for (int i = 0; i < n; i++)
{
scanf("%u", &a[i]);
x ^= a[i];
}
unsigned int mask = x & (~x + 1u);
unsigned int first = 0u;
unsigned int second = 0u;
for (int i = 0; i < n; i++)
{
if (a[i] & mask)
first ^= a[i];
else
second ^= a[i];
}
if (first > second)
{
unsigned int temp = first;
first = second;
second = temp;
}
printf("%u %u", first, second);
free(a);
return 0;
}
19.35 Key Takeaway
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
๐ค Bitwise Programming โ Interview Questions
๐ก 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.
โ๏ธ Bitwise Programming โ Extra Practice Questions
- Find the position of the lowest set bit in a positive integer.
- Reverse all 32 bits of an unsigned integer.
- Check whether two integers have opposite signs using a bitwise expression.
- Generate every subset of a small array using bit masks.
- Find the missing number from 0 to n using XOR.
- Implement a compact feature-control system using eight independent bit flags.