Skip to Content
Course content

237: Common C Interview Questions on Bitwise Operations

Click on the "Edit" button in the top corner of the screen to edit your slide content.

I remember my first big technical interview for a systems role. The interviewer didn't ask me about high-level architecture; instead, they leaned in and asked, "Can you tell me if an integer is a power of two without using a loop or log2()?" I froze. I knew the math, but I forgot the bit-level trick. It’s a classic interview trope because it separates people who think in decimals from people who think in binary.

The "Power of Two" Trap

Let's pretend we're back in that interview. My first instinct is usually to just divide by two repeatedly until I hit one. But that's a loop, and the interviewer explicitly banned loops. So, I'll start playing with binary representations in my head. Let's look at some powers of two:


4: 0100
8: 1000
16: 10000

Notice a pattern? Only one bit is ever set. If I can find a way to check if exactly one bit is set, I've won. I try to think about what happens if I subtract 1 from these numbers. Let's test it in a quick snippet:


int x = 8;
printf("%d in binary: 1000\n", x);
printf("%d in binary: 0111\n", x - 1);

Interesting. Subtracting 1 flips the only set bit to 0 and turns all the trailing zeros into 1s. If I AND these two numbers together, what happens? 1000 & 0111 is 0000. Let's try it with a non-power of two, like 6:


int y = 6; // 0110
int z = 5; // 0101
// 0110 & 0101 = 0100 (Not zero!)

So the logic (x & (x - 1)) == 0 seems to work. But wait—I almost fell into the trap. What happens if x is 0? 0 & -1 is 0. My code would claim 0 is a power of two, which is mathematically wrong. I need to ensure x is greater than 0 first. The final "interview-ready" version is: return x > 0 && (x & (x - 1)) == 0;.

Wrestling with the Hamming Weight

Another common question is counting the "set bits" (the 1s) in an integer. This is often called the Hamming Weight. My immediate thought is to just shift the number 32 times and check the LSB (Least Significant Bit) each time.


int count = 0;
for (int i = 0; i < 32; i++) {
    if ((n >> i) & 1) count++;
}

This works, but it's inefficient. If I have the number 1, I'm still looping 31 more times for zeros. It feels clunky. I remember seeing a trick called Brian Kernighan’s Algorithm. Let's see if I can reconstruct it. Remember how x & (x - 1) cleared the lowest set bit in the previous example? What if I use that in a loop?

Let's trace it with the number 12 (binary 1100):

  • Iteration 1: n = 12 (1100). I do n = n & (n - 1). That's 1100 & 1011, which results in 1000. Count is now 1.
  • Iteration 2: n = 8 (1000). I do 1000 & 0111, which results in 0000. Count is now 2.
  • Loop ends because n is now 0.

This is significantly faster. Instead of 32 iterations, I only iterate as many times as there are 1s. In a production environment, you'd probably use the compiler builtin __builtin_popcount(n), but in an interview, showing you understand the n & (n - 1) trick proves you can manipulate bits effectively.

The XOR Swap Curiosity

You'll occasionally see the "Swap two integers without a temporary variable" question. It's mostly a party trick, but it demonstrates the XOR property: x ^ x = 0 and x ^ 0 = x.

I'll try it out:


int a = 5; // 0101
int b = 9; // 1001

a = a ^ b; // a is now 1100 (the "diff" between them)
b = a ^ b; // b is now 1100 ^ 1001 = 0101 (which was the original a)
a = a ^ b; // a is now 1100 ^ 0101 = 1001 (which was the original b)

It works! But here is a word of caution: never actually do this in real production code. It's harder to read than a simple temp variable, and if a and b happen to point to the same memory location (aliasing), you'll XOR the value with itself and end up with 0. The interviewer wants to see if you know XOR, not if you're willing to write dangerous code.




📋 Practical Task

Exercise: Building a Bit-Field Status Register

In embedded systems, we often pack multiple boolean flags into a single unsigned char to save space. Your task is to implement a small "Status Register" manager.

Write a program that defines the following bit positions:

  • READY_BIT: Bit 0
  • ERROR_BIT: Bit 1
  • BUSY_BIT: Bit 2
  • SYNC_BIT: Bit 3

Implement the following functionality:

  1. Initialize a status` variable to 0.
  2. Set the READY_BIT and SYNC_BIT to 1.
  3. Check if the ERROR_BIT is set (it should be 0).
  4. Toggle the BUSY_BIT to 1.
  5. Clear the READY_BIT back to 0.
  6. Print the final status byte in hexadecimal.

Ensure you use bitwise operators (|, &, ^, ~) for all modifications; do not use addition or subtraction.

Rating
0 0

There are no comments for now.

to be the first to leave a comment.