Skillversitas

C++ Bitwise Operators

Bitwise operators work at the level of individual bits in a number. Each bit in the operands is processed separately, producing new output bits. Bitwise operators are very important in systems programming, binary data manipulation, memory optimization, and embedded systems development.

C++ provides six bitwise operators: AND (&), OR (|), XOR (^), NOT (~), left shift (<<), and right shift (>>). These operators can only be used with integer data types (char, short, int, long).

Bitwise Operator Table

Operator Name Description
& Bitwise AND 1 if both bits are 1
\| Bitwise OR 1 if either bit is 1
^ Bitwise XOR 1 if the two bits differ
~ Bitwise NOT Inverts all bits (1's complement)
<< Left Shift Moves bits to the left
>> Right Shift Moves bits to the right

Bitwise Truth Table

A B A & B A | B A ^ B
0 0 0 0 0
0 1 0 1 1
1 0 0 1 1
1 1 1 1 0

Code Example

#include <iostream>
using namespace std;

void printBinary(int n) {
    for (int i = 7; i >= 0; i--) {
        cout << ((n >> i) & 1);
    }
}

int main() {
    int a = 12, b = 10;

    cout << "=== Bitwise Operators ===" << endl;
    cout << "a = " << a << " (bin: ";
    printBinary(a);
    cout << ")" << endl;
    cout << "b = " << b << " (bin: ";
    printBinary(b);
    cout << ")" << endl;

    // Bitwise AND
    int andResult = a & b;
    cout << "\na & b  = " << andResult << " (bin: ";
    printBinary(andResult);
    cout << ")" << endl;

    // Bitwise OR
    int orResult = a | b;
    cout << "a | b  = " << orResult << " (bin: ";
    printBinary(orResult);
    cout << ")" << endl;

    // Bitwise XOR
    int xorResult = a ^ b;
    cout << "a ^ b  = " << xorResult << " (bin: ";
    printBinary(xorResult);
    cout << ")" << endl;

    // Bitwise NOT
    int notResult = ~a;
    cout << "~a     = " << notResult << endl;

    // Left Shift
    int leftShift = a << 2;
    cout << "\na << 2 = " << leftShift << " (x4)" << endl;
    cout << "a << 1 = " << (a << 1) << " (x2)" << endl;

    // Right Shift
    int rightShift = a >> 2;
    cout << "a >> 2 = " << rightShift << " (/4)" << endl;
    cout << "a >> 1 = " << (a >> 1) << " (/2)" << endl;

    // Bit manipulation techniques
    cout << "\n=== Bit Manipulation Techniques ===" << endl;
    int flags = 0;

    // Set bit 0 (value 1)
    flags |= (1 << 0);
    cout << "Set bit 0 (READ)   : " << flags << endl;

    // Set bit 1 (value 2)
    flags |= (1 << 1);
    cout << "Set bit 1 (WRITE)  : " << flags << endl;

    // Set bit 2 (value 4)
    flags |= (1 << 2);
    cout << "Set bit 2 (EXECUTE): " << flags << endl;

    // Check whether a specific bit is active
    bool hasRead = (flags & (1 << 0)) != 0;
    bool hasWrite = (flags & (1 << 1)) != 0;
    bool hasDelete = (flags & (1 << 3)) != 0;

    cout << "\nREAD active?   : " << hasRead << endl;
    cout << "WRITE active?  : " << hasWrite << endl;
    cout << "DELETE active? : " << hasDelete << endl;

    // Clear bit 1 (remove WRITE)
    flags &= ~(1 << 1);
    cout << "\nAfter clearing bit 1 (WRITE): " << flags << endl;

    // Toggle bit 0
    flags ^= (1 << 0);
    cout << "After toggling bit 0 (READ): " << flags << endl;

    // Swap without a temporary variable
    cout << "\n=== Swap Without a Temporary Variable ===" << endl;
    int x = 25, y = 37;
    cout << "Before: x = " << x << ", y = " << y << endl;
    x ^= y;
    y ^= x;
    x ^= y;
    cout << "After: x = " << x << ", y = " << y << endl;

    return 0;
}

Code Explanation

  • Bitwise AND (&): Produces 1 only if both bits are 1. Useful for masking (extracting certain bits).
  • Bitwise OR (|): Produces 1 if either bit is 1. Useful for setting specific bits.
  • Bitwise XOR (^): Produces 1 if the two bits differ. Useful for toggling and swapping.
  • Bitwise NOT (~): Inverts all bits. A 1's complement operation.
  • Left Shift (<<): Moves all bits to the left. Each shift doubles the value. Example: a << 1 is the same as a * 2.
  • Right Shift (>>): Moves all bits to the right. Each shift divides the value by 2. Example: a >> 1 is the same as a / 2.

Everyday Use Cases

Permission System (Access Rights):

#include <iostream>
#include <string>
using namespace std;

// Definition of permission flags
const int PERM_READ    = 1 << 0;  // 0001 = 1
const int PERM_WRITE   = 1 << 1;  // 0010 = 2
const int PERM_EXECUTE = 1 << 2;  // 0100 = 4
const int PERM_DELETE  = 1 << 3;  // 1000 = 8

string permissionToString(int perm) {
    string result = "";
    if (perm & PERM_READ)    result += "R";
    if (perm & PERM_WRITE)   result += "W";
    if (perm & PERM_EXECUTE) result += "X";
    if (perm & PERM_DELETE)  result += "D";
    if (result.empty()) result = "-";
    return result;
}

int main() {
    // User 1: has all permissions
    int user1 = PERM_READ | PERM_WRITE | PERM_EXECUTE | PERM_DELETE;

    // User 2: read and execute only
    int user2 = PERM_READ | PERM_EXECUTE;

    // User 3: no permissions
    int user3 = 0;

    cout << "=== Permission System ===" << endl;
    cout << "User 1: " << permissionToString(user1) << endl;
    cout << "User 2: " << permissionToString(user2) << endl;
    cout << "User 3: " << permissionToString(user3) << endl;

    // Check specific permissions
    cout << "\n=== Permission Check ===" << endl;
    cout << "Can User 2 write? " << ((user2 & PERM_WRITE) ? "Yes" : "No") << endl;
    cout << "Can User 1 delete? " << ((user1 & PERM_DELETE) ? "Yes" : "No") << endl;

    // Remove the WRITE permission from User 1
    user1 &= ~PERM_WRITE;
    cout << "\nUser 1 after removing WRITE: " << permissionToString(user1) << endl;

    // Add the WRITE permission to User 2
    user2 |= PERM_WRITE;
    cout << "User 2 after adding WRITE: " << permissionToString(user2) << endl;

    // Even/odd checker without modulus
    cout << "\n=== Even/Odd Check ===" << endl;
    for (int i = 0; i <= 10; i++) {
        string parity = (i & 1) ? "Odd" : "Even";
        cout << i << " = " << parity << endl;
    }

    return 0;
}

Conclusion

Bitwise operators (&, |, ^, ~, <<, >>) work at the level of individual bits. These operators are very efficient and are used extensively in permission systems, flag manipulation, performance optimization, and other binary operations. Common techniques include setting bits with OR, clearing bits with AND NOT, and toggling with XOR. Left shift is equivalent to multiplication and right shift is equivalent to division, making them fast optimization techniques.