SyntaxStudy
Sign Up
C Bitwise Operators
C Beginner 1 min read

Bitwise Operators

Bitwise operators work directly on the binary representation of integer values. The six bitwise operators in C are: `&` (AND), `|` (OR), `^` (XOR), `~` (NOT/complement), `<<` (left shift), and `>>` (right shift). These are essential tools in systems programming, embedded development, and anywhere you need to manipulate individual bits — such as setting hardware register flags or packing multiple small values into a single integer. Bitwise AND is often used to mask off bits or test whether a particular bit is set. Bitwise OR sets specific bits. XOR toggles bits — XORing a value with itself always yields zero, which is used in some optimizations and data-recovery schemes. The NOT operator inverts every bit. Left-shifting by `n` is equivalent to multiplying by 2^n (for positive values); right-shifting by `n` divides by 2^n, though the behaviour of right-shifting a negative signed integer is implementation-defined. A common idiom is using an `int` as a set of boolean flags, where each bit represents one flag. Macros using `1 << n` create bit masks for specific positions. Testing, setting, and clearing individual bits with `&`, `|`, and `&~` respectively is idiomatic C that you will find throughout OS kernels, device drivers, and networking code.
Example
#include <stdio.h>

/* Define flag bits using left-shift */
#define FLAG_READ    (1 << 0)   /* bit 0: 0000 0001 */
#define FLAG_WRITE   (1 << 1)   /* bit 1: 0000 0010 */
#define FLAG_EXEC    (1 << 2)   /* bit 2: 0000 0100 */

void print_binary(unsigned int n)
{
    for (int i = 7; i >= 0; i--)
        putchar((n >> i) & 1 ? '1' : '0');
    putchar('\n');
}

int main(void)
{
    unsigned int a = 0b00001100;  /* 12 */
    unsigned int b = 0b00001010;  /* 10 */

    printf("a & b  = %u  -> ", a & b);  print_binary(a & b);  /* 8  */
    printf("a | b  = %u  -> ", a | b);  print_binary(a | b);  /* 14 */
    printf("a ^ b  = %u  -> ", a ^ b);  print_binary(a ^ b);  /* 6  */
    printf("~a     = %u  -> ", ~a & 0xFF); print_binary(~a & 0xFF);
    printf("a << 2 = %u  -> ", a << 2); print_binary(a << 2); /* 48 */
    printf("a >> 1 = %u  -> ", a >> 1); print_binary(a >> 1); /* 6  */

    /* Flags example */
    unsigned int perms = FLAG_READ | FLAG_WRITE;
    printf("\nRead?  %s\n", (perms & FLAG_READ)  ? "yes" : "no");
    printf("Write? %s\n",   (perms & FLAG_WRITE) ? "yes" : "no");
    printf("Exec?  %s\n",   (perms & FLAG_EXEC)  ? "yes" : "no");

    perms |= FLAG_EXEC;           /* set exec bit   */
    perms &= ~FLAG_WRITE;         /* clear write bit */
    printf("After update — Write? %s  Exec? %s\n",
           (perms & FLAG_WRITE) ? "yes" : "no",
           (perms & FLAG_EXEC)  ? "yes" : "no");

    return 0;
}