Table of Contents
KEY TAKEAWAYS
- An 8-bit variable can store 8 independent boolean flags, saving memory compared to separate variables
- Set a flag with OR (
flags |= FLAG), clear with AND-NOT (flags &= ~FLAG), toggle with XOR (flags ^= FLAG) - Check a flag with AND:
if (flags & FLAG)returns non-zero when the flag is set - This technique is widely used in embedded systems for status registers and configuration bits
Understanding Bits and Bytes
Before we start, let’s understand what bits and bytes are. A bit is the most basic unit of information in computing and digital communications. The name is a portmanteau of binary digit. The bit represents a logical state with one of two possible values. These values are most commonly represented as either “1” or “0”.A byte is a unit of digital information that most commonly consists of 8 bits. Hence, an 8-bit variable can store values from 0 to 255 (2^8 – 1) in decimal or 00 to FF in hexadecimal.The Essence of Bitwise Flag Manipulation
A lot of beginners usually use individual ‘int’ or ‘uint8_t’ for one flag. Some examples are:int data_received_flag = 0; int data_transmitted_flag = 0; int threshold_crossed_flag = 0; OR uint8_t data_received_flag = 0; uint8_t data_transmitted_flag = 0; uint8_t threshold_crossed_flag = 0;In this approach, the work gets done but there is a lot of wastage of memory. For some Microcontrollers, we deal with memory in the range of single digit KB. Wasting bytes is like a crime here.But there is a better way to do it. The idea here is that each bit in an 8-bit variable can be treated as a separate flag – this gives us 8 flags in total. To do this, we use bitwise operations – specifically, the bitwise AND (&), OR (|), and NOT (~) operations.
Setting a Flag with Bitwise Flag Manipulation
Setting a flag is done with the bitwise OR operation. This ensures that a specific bit is set to 1, no matter what it was previously. For instance, to set the second bit in our 8-bit variable, we would do:flags |= 0b00000010;or, it’s often more readable to use hexadecimal or a bit shift operation:
flags |= 0x02; // hexadecimal flags |= (1 << 1); // bit shift
Checking a Flag with Bitwise Flag Manipulation
To check if a flag is set, we use the bitwise AND operation. This will return a non-zero result if the flag is set, and 0 if the flag is not set. For example, to check the second bit:if (flags & 0x02) {
// The second bit is set
} else {
// The second bit is not set
}
Clearing a Flag with Bitwise Flag Manipulation
To clear a flag (set it to 0), we use the bitwise AND operation with the bitwise NOT operation. This ensures that a specific bit is set to 0, no matter what it was previously. For instance, to clear the second bit:flags &= ~0x02;or using a bit shift operation:
flags &= ~(1 << 1);
Flipping a Flag with Bitwise Flag Manipulation
To flip a flag (change from 0 to 1, or 1 to 0), we use the bitwise XOR operation. This will set a specific bit to its opposite, no matter what it was previously:flags ^= 0x02;or using a bit shift operation:
flags ^= (1 << 1);
Defining Function like Macros for Checking, setting and clearing flags:
Doing the operations multiple times in a program can get cumbersome and also prone to errors and bug. So, we can define some C macros that can be used to set, reset, and check flags in an 8-bit variable. These macros use the same bitwise operations we discussed earlier.// Macro to set a flag #define FLAG_SET(var, flag) ((var) |= (1 << (flag))) // Macro to clear a flag #define FLAG_CLEAR(var, flag) ((var) &= ~(1 << (flag))) // Macro to check a flag #define FLAG_CHECK(var, flag) ((var) & (1 << (flag))) // Macro to toggle a flag #define FLAG_TOGGLE(var, flag) ((var) ^= (1 << (flag)))Check out How to use #define Macros in C – NerdyElectronicsThese macros can be used in the code as follow:
uint8_t flags = 0; // Our 8-bit variable that will store the flags
// Set the 2nd flag
FLAG_SET(flags, 1);
// Check the 2nd flag
if (FLAG_CHECK(flags, 1)) {
printf("The 2nd flag is set.\n");
} else {
printf("The 2nd flag is not set.\n");
}
// Clear the 2nd flag
FLAG_CLEAR(flags, 1);
// Toggle the 2nd flag
FLAG_TOGGLE(flags, 1);
Defining Macros for individual Flags:
We can make it more readable and easy to work with by defining MACROS for each individual flag:#define data_received_flag 0 #define data_transmitted_flag 1 #define threshold_crossed_flag 2By defining these flags as MACROS, what we are trying to do is as shown in the following diagram:

#define data_received_flag 0
#define data_transmitted_flag 1
#define threshold_crossed_flag 2
// Macro to set a flag
#define FLAG_SET(var, flag) ((var) |= (1 << (flag)))
// Macro to clear a flag
#define FLAG_CLEAR(var, flag) ((var) &= (1 << (flag)))
// Macro to check a flag
#define FLAG_CHECK(var, flag) ((var) & (1 << (flag)))
// Macro to toggle a flag
#define FLAG_TOGGLE(var, flag) ((var) ^= (1 << (flag)))
int main()
{
uint8_t flags = 0; // Our 8-bit variable that will store the flags
// Set the 2nd flag
FLAG_SET(flags, data_received_flag);
FLAG_SET(flags, data_transmitted_flag);
// Check the 2nd flag
if (FLAG_CHECK(flags, data_transmitted_flag )) {
printf("The 2nd flag is set.\n");
} else {
printf("The 2nd flag is not set.\n");
}
// Clear the 2nd flag
FLAG_CLEAR(flags, data_transmitted_flag );
// Toggle the 2nd flag
FLAG_TOGGLE(flags, data_transmitted_flag );
return 0;
}Conclusion
This method is very space efficient, as it allows us to store 8 flags in a single byte. It’s also computationally efficient, as bitwise operations are very fast. However, it can be a bit harder to read than simply using separate variables. Use it a few times and it becomes very very easy.
Vivek Bhageria — Lead Firmware R&D Engineer, 12+ years. Ex-Bosch (automotive powertrain), MusicTribe (real-time audio), medical devices. M.Tech BITS Pilani. I write at NerdyElectronics — practical, register-level embedded systems for engineers who want to understand what’s actually happening under the hood.





