Skip to Content
Course content

183: Setting, Clearing, and Toggling Bits

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

When you're working close to the hardware—or just trying to squeeze every bit of performance out of a program—you can't afford to waste a whole int just to store a true/false flag. That's why we use bitmasks. I've spent years debugging driver code where one wrong bit flip crashed the entire system, so let's make sure you have these patterns down cold.

How do I turn on a specific bit without changing anything else?

To "set" a bit, you use the bitwise OR operator (|). The logic here is simple: anything ORed with 1 becomes 1, and anything ORed with 0 stays exactly what it was. If you want to flip the 3rd bit of a register to "on," you create a mask with a 1 in that position and 0s everywhere else.

unsigned char status = 0b00000000; // Everything off
int bit_to_set = 3;

// Shift 1 left by 3 positions to get 0b00001000
status |= (1 << bit_to_set); 

// status is now 0b00001000

I usually suggest using the |= shorthand. It's cleaner and it's what you'll see in almost every professional C codebase. Just remember: OR is for adding or enabling flags.

What's the trick to turning a bit off while keeping the others untouched?

Clearing a bit is slightly more counter-intuitive because you can't just OR it with 0. To force a bit to 0, you need to AND it with a mask where every bit is 1 except for the one you want to kill. We achieve this by taking our "set" mask and flipping it using the bitwise NOT operator (~).

unsigned char status = 0b00001111; // Several flags are on
int bit_to_clear = 2;

// (1 << 2) is 0b00000100
// ~(1 << 2) is 0b11111011
status &= ~(1 << bit_to_clear);

// status is now 0b00001011

Think of ~(1 << n) as creating a "hole" in a wall of ones. When you AND your variable with that hole, only the bit at that specific position gets wiped out. I've seen beginners try to subtract the value instead, but don't do that—if the bit is already 0, subtraction will wrap around and ruin your entire byte.

Is there a way to flip a bit back and forth without using an if/else?

If you're writing a function to blink an LED or toggle a setting, you don't want to check if the bit is 1 to make it 0, or 0 to make it 1. That's too much boilerplate. Instead, use the XOR operator (^). XOR returns 1 only if the bits are different. This means XORing a bit with 1 will always flip its current state.

unsigned char status = 0b00000001; // Only bit 0 is on
int bit_to_toggle = 0;

status ^= (1 << bit_to_toggle); // Now it's 0b00000000
status ^= (1 << bit_to_toggle); // Now it's 0b00000001 again

It's elegant, fast, and effectively a "light switch" for your data. Whether you're toggling a "Mute" flag in an audio engine or flipping a pin on a microcontroller, ^= is your best friend.




📋 Practical Task

The Virtual LED Control Panel

You are writing a driver for a virtual control panel that uses a single unsigned char (8 bits) to track the state of 8 LEDs. Your task is to implement three specific functions to manage these LEDs without affecting the other bits in the byte.

  • void led_on(unsigned char *panel, int led_index): Set the bit at led_index to 1.
  • void led_off(unsigned char *panel, int led_index): Set the bit at led_index to 0.
  • void led_toggle(unsigned char *panel, int led_index): Flip the current state of the bit at led_index.

Test your implementation by starting with a panel of 0x00, turning on LEDs 0 and 7, toggling LED 0 off, and then toggling LED 3 on. The final value of the panel should be 0x88 (binary 10001000).

Rating
0 0

There are no comments for now.

to be the first to leave a comment.