For working professionals
For fresh graduates
More
5. Array in C
13. Boolean in C
18. Operators in C
33. Comments in C
38. Constants in C
41. Data Types in C
49. Double In C
58. For Loop in C
60. Functions in C
70. Identifiers in C
81. Linked list in C
83. Macros in C
86. Nested Loop in C
97. Pseudo-Code In C
100. Recursion in C
103. Square Root in C
104. Stack in C
106. Static function in C
107. Stdio.h in C
108. Storage Classes in C
109. strcat() in C
110. Strcmp in C
111. Strcpy in C
114. String Length in C
115. String Pointer in C
116. strlen() in C
117. Structures in C
119. Switch Case in C
120. C Ternary Operator
121. Tokens in C
125. Type Casting in C
126. Types of Error in C
127. Unary Operator in C
128. Use of C Language
While debugging C programs, it’s common to face challenges related to performance, memory, or low-level data processing. In such cases, using Bitwise Operators in C often brings surprising benefits. They let you manipulate data at the binary level, offering speed and control where traditional operators fall short.
When writing systems software, device drivers, or embedded code, every byte and bit counts. Bitwise Operators in C empower programmers to perform operations that directly interface with hardware or optimize performance in critical sections. Their compactness and speed make them essential in certain domains of C programming.
Pursue our Software Engineering courses to get hands-on experience!
Bitwise operators perform operations on the individual bits of integers. These operators treat data as sequences of 0s and 1s. Understanding how to convert decimal numbers to binary is essential when working with bitwise operators in C. They are mostly used with int, char, short, or long types. The result is a new value computed bit by bit, following a predefined logic.
Syntax of Bitwise Operators in C
result = operand1 <bitwise_operator> operand2;
Here’s a basic usage example:
#include <stdio.h>
int main() {
int a = 5; // Binary: 0101
int b = 3; // Binary: 0011
int result = a & b;
printf("Result = %d\n", result);
return 0;
}
Output:
Result = 1
Explanation:The binary AND of 0101 and 0011 is 0001, which is 1 in decimal. The & operator compares each bit and returns 1 only if both bits are 1.
Take your skills to the next level with these top programs:
C provides six types of bitwise operators. Each performs a unique binary operation on corresponding bits of the operands. These include:
This operator performs a logical AND operation on each pair of corresponding bits.Truth Table:
A | B | A & B |
0 | 0 | 0 |
0 | 1 | 0 |
1 | 0 | 0 |
1 | 1 | 1 |
Example:
#include <stdio.h>
int main() {
int x = 6; // Binary: 0110
int y = 4; // Binary: 0100
int res = x & y;
printf("Bitwise AND = %d\n", res);
return 0;
}
Output:
Bitwise AND = 4
Explanation: Only the second-highest bit is common in both numbers. So, 0110 & 0100 = 0100, which is 4.
This operator returns 1 if at least one of the bits is 1.
Truth Table:
A | B | A | B |
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 1 |
Example:
#include <stdio.h>
int main() {
int x = 5; // Binary: 0101
int y = 3; // Binary: 0011
int res = x | y;
printf("Bitwise OR = %d\n", res);
return 0;
}
Output:
Bitwise OR = 7
Explanation: 0101 | 0011 = 0111. The result is 7 in decimal.
The XOR operator returns 1 only if the bits are different.
Truth Table:
A | B | A ^ B |
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 0 |
Example:
#include <stdio.h>
int main() {
int a = 9; // Binary: 1001
int b = 5; // Binary: 0101
int result = a ^ b;
printf("Bitwise XOR = %d\n", result);
return 0;
}
Output:
Bitwise XOR = 12
Explanation: 1001 ^ 0101 = 1100, which is 12 in decimal. XOR is often used for toggling bits.
Must Read: XOR in Python article!
This is a unary operator. It inverts all bits of the operand.
Truth Table:
A | ~A |
0 | 1 |
1 | 0 |
Example:
#include <stdio.h>
int main() {
int x = 8; // Binary: 00001000
int res = ~x;
printf("Bitwise NOT = %d\n", res);
return 0;
}
Output:
Bitwise NOT = -9
Explanation: The NOT operator flips each bit. In signed integer representation (2's complement), ~8 becomes -9.
This operator shifts all bits to the left by a specified number of positions.
Truth Table for 1-bit Left Shift:
Input | Shift | Result |
1 | <<1 | 10 |
10 | <<1 | 100 |
100 | <<2 | 0001 0000 |
Example:
#include <stdio.h>
int main() {
int num = 2; // Binary: 0010
int shifted = num << 2;
printf("Left Shift = %d\n", shifted);
return 0;
}
Output:
Left Shift = 8
Explanation: Shifting 0010 two positions left gives 1000, which equals 8.
This shifts bits to the right. The vacant positions are filled based on the system.
Truth Table for 1-bit Right Shift:
Input | Shift | Result |
1 | >>1 | 0 |
100 | >>1 | 10 |
1000 | >>3 | 1 |
Example:
#include <stdio.h>
int main() {
int num = 16; // Binary: 00010000
int result = num >> 2;
printf("Right Shift = %d\n", result);
return 0;
}
Output:
Right Shift = 4
Explanation: Shifting 00010000 two positions to the right gives 00000100, or 4 in decimal.
Bitwise operators in C are not limited to theory. They are used widely in writing optimized and hardware-near code. With the help of these operators, developers can manipulate bits directly. This section includes beginner to advanced examples to help you understand their practical use in real-world scenarios. We also provide the output and an explanation with each example.
Let's begin with a basic example. We'll check if a number is even or odd using the bitwise AND (&) operator.
#include <stdio.h>
int main() {
int num = 11;
if (num & 1)
printf("%d is Odd\n", num);
else
printf("%d is Even\n", num);
return 0;
}
Output:
11 is Odd
Explanation: In binary, 11 is 1011. The least significant bit (LSB) tells us if the number is even or odd.
Here, num & 1 isolates the last bit. If the result is 1, it’s odd. This approach is faster than using modulus (%) for checking parity.
Now let’s use bitwise shift (<<) and AND (&) together. We’ll check whether the 3rd bit (from the right, 0-indexed) is set.
#include <stdio.h>
int main() {
int num = 42; // Binary: 00101010
int mask = 1 << 2; // Shift 1 to the 3rd bit position => 00000100
if (num & mask)
printf("3rd bit is set in %d\n", num);
else
printf("3rd bit is not set in %d\n", num);
return 0;
}
Output:
3rd bit is set in 42
Explanation: We shift 1 left by 2 positions, making the mask 00000100 (i.e., 4). Then we use num & mask. If the result is non-zero, it means the 3rd bit is 1. This method is useful for reading specific flags or status bits in low-level programming like microcontroller registers.
Let’s simulate a permission system using XOR (^). Suppose we are managing read, write, and execute permissions using bits:
We’ll use XOR to toggle a permission.
#include <stdio.h>
#define READ 0x4 // 0100
#define WRITE 0x2 // 0010
#define EXEC 0x1 // 0001
int main() {
int permissions = 0x7; // All permissions active: 0111
printf("Initial Permissions = %d\n", permissions);
// Revoke write permission using XOR
permissions ^= WRITE;
printf("Permissions after toggling WRITE = %d\n", permissions);
// Restore write permission
permissions ^= WRITE;
printf("Permissions after restoring WRITE = %d\n", permissions);
return 0;
}
Output:
Initial Permissions = 7
Permissions after toggling WRITE = 5
Permissions after restoring WRITE = 7
Explanation: Initially, all bits are set (7 = 0111). Using XOR with WRITE (2 = 0010):
This approach is widely used in access control systems, flag toggling, and embedded programming where performance and precision matter.
Bitwise operators in C offer a wide range of advantages, especially in performance-critical applications. They are an essential tool when working close to the hardware or when memory and speed are important constraints.
1. Extremely Fast Execution
Bitwise operations execute much faster than arithmetic or logical operations. They operate directly at the binary level, which means no conversion or extra CPU cycles are needed. In time-sensitive systems like embedded devices or game engines, this speed difference matters.
2. Efficient Use of Memory
Since each bit can represent a unique flag or state, developers can store multiple pieces of information in a single byte or integer. This is useful in resource-limited systems like microcontrollers. You can store 8 flags in one char, and 32 flags in one int.
Also explore the Difference Between Microcontroller and Microprocessor article!
3. Useful for Flag Management
You can use individual bits to represent flags. Bitwise AND (&), OR (|), and XOR (^) make it easy to set, clear, or toggle those flags. This method simplifies permission handling, status tracking, and control registers.
4. Widely Used in Embedded and Low-Level Programming
Bitwise operations are used to manipulate I/O ports, control bits in registers, and interact with memory-mapped hardware. Their directness and speed make them ideal for such low-level tasks.
5. Compact Code for Specific Tasks
Instead of writing multiple if-else conditions or switch blocks, bitwise logic can compactly represent logic for masks, toggles, and state checks. This results in smaller, cleaner, and faster code.
6. Used in Algorithms and Optimization
Bitwise operators are core to many advanced algorithms:
These techniques are used in cryptography, graphics, networking, and compilers.
7. Avoid Overflow Issues in Certain Scenarios
Bitwise operations don’t involve carry or sign bits like arithmetic operations. So in some cases, especially with unsigned values, you can prevent overflow or undefined behavior.
While bitwise operators in C are powerful, they come with several drawbacks that can lead to issues if not used carefully. Their low-level nature often introduces complexity and reduces code clarity.
1. Harder to Understand and Debug
Bitwise operations are not intuitive, especially for beginners. Expressions like value & 0xF0 or flags ^ (1 << 3) are hard to interpret without binary knowledge. Debugging such code becomes difficult without step-by-step tracing.
2. Code Readability Suffers
Unlike arithmetic or logical expressions, bitwise expressions don't convey intent clearly. For example, x = x & ~0x08 clears the fourth bit, but to most readers, the purpose is unclear. This lack of readability increases the maintenance burden.
3. Error-Prone for Large Data Manipulations
Manipulating multiple bits increases the chances of errors. Off-by-one shifts, incorrect masking, or wrong precedence can introduce bugs. These bugs are often silent and don't trigger compile-time warnings.
4. Non-Portable in Some Cases
Different systems might have different endianness or integer sizes. Bit-level manipulations relying on layout or specific memory patterns can behave unexpectedly across platforms. This affects portability, especially in embedded or cross-platform projects.
5. Limited to Integral Types
Bitwise operators only work with integers. They cannot be applied to float, double, or complex structures. This restricts their use in mathematical, scientific, or high-level data manipulation tasks.
6. Not Compiler-Safe with Signed Integers
Shifting signed integers, especially with right shift (>>), can result in implementation-defined behavior. In some systems, it performs arithmetic shift; in others, logical. This inconsistency can lead to incorrect results or bugs.
7. Requires Manual Bitmask Management
Creating and maintaining bitmasks manually increases code complexity. Using 1 << n or hexadecimal masks like 0x1F requires care and discipline. A single mistake can alter program logic drastically.
Bitwise operators are efficient but easy to misuse. Knowing operator precedence and associativity is crucial for correctly evaluating complex bitwise expressions. Developers often make subtle mistakes that lead to incorrect results or hard-to-trace bugs. Let’s explore the most common pitfalls when working with bitwise operators in C.
1. Using Bitwise Operators Instead of Logical Ones
Beginners often confuse & with && or | with ||. While both operate on similar-looking symbols, their behaviors are entirely different.
Incorrect Code:
int a = 5, b = 10;
if (a & b) {
printf("True\n");
}
Output:
True
Explanation: This doesn’t check if both a and b are non-zero. Instead, it performs a bitwise AND. The result is 0 only if no bits match. To check logical conditions, use &&.
2. Ignoring Operator Precedence
Bitwise operators have lower precedence than arithmetic or comparison operators. Without parentheses, expressions may not evaluate as expected.
Incorrect Code:
if (x & 1 == 0)
Output: May give unexpected results.
Explanation: Here, 1 == 0 evaluates first (resulting in false, i.e., 0), then x & 0 is checked. Use parentheses: if ((x & 1) == 0) to test for even numbers.
3. Shifting by Negative or Oversized Values
Right or left shifting a value by a negative number or by a shift amount ≥ bit-width leads to undefined behavior.
Example:
int x = 1;
x = x << 32;
Output: Undefined behavior (varies by compiler/system).
Explanation: On a 32-bit system, shifting by 32 or more is invalid. Always ensure the shift value is within valid range.
4. Using Bitwise NOT on Unsigned Data Improperly
The ~ operator inverts every bit. When applied to unsigned types, it can produce large, unexpected values.
Example:
unsigned int a = 5;
printf("%u", ~a);
Output: 4294967290 (on a 32-bit system)
Explanation: ~5 becomes 0xFFFFFFFA. Be cautious when using ~ with unsigned types, especially in comparisons.
5. Forgetting to Use Proper Bitmasking
When working with flags, developers sometimes forget to mask bits correctly before comparison or toggling.
Incorrect Code:
if (flags == 0x04)
Explanation: This checks if flags equals 0x04, not whether the third bit is set. Correct way:
if (flags & 0x04)
6. Misusing Compound Bitwise Assignments
Operators like |=, &=, ^=, or <<= can introduce bugs if the logic isn’t understood fully.
Example:
int mask = 0x01;
flags |= mask;
flags &= ~mask;
Explanation: The first sets the bit, the second clears it. If you confuse |= with &=, you’ll unintentionally toggle or unset the bit.
7. Overcomplicating Simple Logic
Bitwise logic is elegant when used properly but can make simple logic unnecessarily complex.
Example:
if ((val & 0x01) && !(val & 0x02))
Explanation: This is harder to read than a descriptive approach using named masks or boolean flags. Prefer meaningful variable names and constants to improve clarity.
Bitwise operators in C provide low-level control over data, making them powerful tools in a programmer’s toolkit. When used correctly, they allow for highly efficient and optimized code, especially in system programming, embedded development, and bit manipulation tasks.
Understanding and practicing bitwise operations not only enhances your problem-solving skills but also deepens your grasp of how computers process data at the bit level. Just remember to be cautious with precedence, signed shifts, and operator confusion.
Bitwise operators in C may seem intimidating at first, but with the right knowledge and practice, they become reliable allies in writing clean and efficient code.
Bitwise operators are used in embedded systems, encryption algorithms, device drivers, graphics programming, and error detection. They help control hardware, manage flags, and optimize memory and performance in resource-constrained environments.
Bitwise operators manipulate individual bits within variables, whereas logical operators evaluate entire expressions as true or false. Bitwise operators return integers, while logical ones return either 0 (false) or 1 (true) after evaluating conditions.
In embedded systems, bitwise operators are used to read or modify hardware register values, set or clear specific bits, manage control flags, and optimize performance in low-memory or real-time applications.
No, bitwise operators in C only work with integral types such as int, char, or long. They cannot be directly applied to float or double variables without typecasting or using memory manipulation techniques.
Bit masking involves using bitwise operators with specific bit patterns to isolate, set, or clear certain bits. It’s especially useful for flag operations, configuration settings, and hardware interaction in system-level programming.
Bitwise AND (&) helps check if a specific bit is set by masking other bits. If the result is non-zero, the targeted bit is set. It’s a fast and reliable method used in flag checking.
Yes. << performs a left shift, effectively multiplying the value by powers of 2. >> performs a right shift, dividing the value by powers of 2 and preserving or discarding sign bits depending on data type.
Shifting a value by a negative number or a value equal to or greater than the variable’s bit width results in undefined behavior. Always ensure the shift amount is within a valid range for safe operation.
Yes, bitwise operations are often faster than arithmetic or logical operations. They work directly at the hardware level, which helps optimize performance, especially in time-critical or low-level code like drivers or firmware.
Most bitwise operations are portable. However, signed right shifts and system endianness may cause differences. To ensure portability, avoid shifting signed integers and always test behavior on target platforms.
The XOR operator (^) is commonly used for toggling bits, implementing bit-level encryption, or finding unique elements in arrays. It returns 1 only when the bits differ, making it useful for comparison logic.
To set a bit, use OR with a mask (val | mask). To clear a bit, use AND with the inverse of the mask (val & ~mask). These methods help manipulate flags efficiently in memory.
Using ~ on unsigned integers flips all bits, potentially producing large values due to the lack of sign extension. It’s important to apply it cautiously, especially in conditions or range checks.
You can toggle a bit using the XOR operator. For example, value ^= mask; flips the targeted bit without affecting others. It’s a simple and fast method to alternate flag states.
Yes. Bitwise operations like XOR, AND, and shifts are core components in many encryption and hashing algorithms. They enable fast, low-level data manipulation essential for cryptographic transformations.
Take a Free C Programming Quiz
Answer quick questions and assess your C programming knowledge
Author|900 articles published
Previous
Next
Start Learning For Free
Explore Our Free Software Tutorials and Elevate your Career.
Talk to our experts. We are available 7 days a week, 9 AM to 12 AM (midnight)
Indian Nationals
1800 210 2020
Foreign Nationals
+918068792934
1.The above statistics depend on various factors and individual results may vary. Past performance is no guarantee of future results.
2.The student assumes full responsibility for all expenses associated with visas, travel, & related costs. upGrad does not provide any a.