๐ข 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.
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.
19.2 Binary Representation โ The Foundation
For an 8-bit unsigned value, each position represents a power of 2:
| Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|---|---|---|---|---|---|---|---|---|
| Weight | 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 |
For example, 10 is 00001010 because 8 + 2 = 10.
19.3 The Bitwise Operators
| 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.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
| A | B | A & B |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 0 |
| 1 | 0 | 0 |
| 1 | 1 | 1 |
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.
19.8 XOR Truth Table
| A | B | A ^ B |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 0 |
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.
~x = -x - 1Therefore:
~5 = -5 - 1 = -6~ 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.
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.
value & maskvalue | maskvalue ^ maskvalue & ~mask19.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
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;
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 = 0x ^ 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
| 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 |
& 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
~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.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.
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:
- 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.
- Shifting by five positions yields the value 32.
- Bitwise OR sets that flag in value.
19.33 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 != 0 && (n & (n - 1)) == 0 โ Power-of-two test for an unsigned value
๐ฌ 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.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.
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.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.
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.36 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.