⬅ Previous Next ➡

Additional Concepts

Additional Concepts: Bitwise Operators & Low-level Operations in C
  • Bitwise operators work directly on the binary (bit) representation of integers.
  • They are used in low-level programming like embedded systems, device drivers, networking, and performance optimizations.
  • Common tasks: setting/clearing bits, masking, shifting, toggling, and checking flags.

1) Bitwise Operators in C

  • & AND
  • | OR
  • ^ XOR
  • ~ NOT (bitwise complement)
  • << Left shift
  • >> Right shift
#include <stdio.h>

int main() {
    unsigned int a = 5;  // 0101
    unsigned int b = 3;  // 0011

    printf("a & b = %u\n", a & b); // 0001 = 1
    printf("a | b = %u\n", a | b); // 0111 = 7
    printf("a ^ b = %u\n", a ^ b); // 0110 = 6
    printf("~a    = %u\n", (unsigned int)(~a));

    printf("a << 1 = %u\n", a << 1); // 1010 = 10
    printf("a >> 1 = %u\n", a >> 1); // 0010 = 2

    return 0;
}

2) Bit Masking (Check / Set / Clear / Toggle Bits)

  • Mask is a bit pattern used to isolate or modify specific bits.
  • Common operations:
    • Check bit: (n & mask) != 0
    • Set bit: n = n | mask
    • Clear bit: n = n & (~mask)
    • Toggle bit: n = n ^ mask
#include <stdio.h>

int main() {
    unsigned int n = 10;       // 1010
    unsigned int mask = 1u << 1; // bit 1 (0010)

    // Check bit 1
    if ((n & mask) != 0) {
        printf("Bit 1 is ON\n");
    } else {
        printf("Bit 1 is OFF\n");
    }

    // Set bit 0
    n = n | (1u << 0); // 1011
    printf("After set bit 0: %u\n", n);

    // Clear bit 3
    n = n & ~(1u << 3); // clears highest bit in 1011 -> 0011
    printf("After clear bit 3: %u\n", n);

    // Toggle bit 1
    n = n ^ (1u << 1);
    printf("After toggle bit 1: %u\n", n);

    return 0;
}

3) Shifts as Fast Multiply/Divide (Careful Use)

  • Left shift by k: n << k ≈ n × 2^k
  • Right shift by k: n >> k ≈ n ÷ 2^k (for unsigned / positive values)
#include <stdio.h>

int main() {
    unsigned int n = 6;

    printf("n = %u\n", n);
    printf("n*2 = %u\n", n << 1);
    printf("n/2 = %u\n", n >> 1);

    return 0;
}

4) Low-level Concepts (Supporting)

  • Endianness: byte order in memory (little-endian vs big-endian).
  • Flags: bits used to store multiple true/false states in one integer.
  • Bit-fields: store small-width values inside a struct (compiler dependent).
4.1) Flags Example
  • Store multiple ON/OFF settings in one integer.
#include <stdio.h>

#define FLAG_READ   (1u << 0)
#define FLAG_WRITE  (1u << 1)
#define FLAG_EXEC   (1u << 2)

int main() {
    unsigned int perm = 0;

    perm |= FLAG_READ;
    perm |= FLAG_WRITE;

    if (perm & FLAG_READ)  printf("READ allowed\n");
    if (perm & FLAG_WRITE) printf("WRITE allowed\n");
    if (perm & FLAG_EXEC)  printf("EXEC allowed\n");

    return 0;
}
4.2) Bit-field Example (Basic)
#include <stdio.h>

struct Status {
    unsigned int ready : 1;
    unsigned int error : 1;
    unsigned int mode  : 2; // 0-3
};

int main() {
    struct Status s = {1, 0, 2};

    printf("ready=%u error=%u mode=%u\n", s.ready, s.error, s.mode);
    return 0;
}

5) Quick Notes

  • Use unsigned types when doing bit operations to avoid sign issues.
  • Masking is the most common real-world use of bitwise operators.
  • Shifts are fast but should be used carefully (overflow/negative values).
  • Bitwise concepts are important for embedded and system-level programming.
Additional Concepts: Bitwise Operators & Low-level Operations in C
  • Bitwise operators work directly on the binary (bit) representation of integers.
  • They are used in low-level programming like embedded systems, device drivers, networking, and performance optimizations.
  • Common tasks: setting/clearing bits, masking, shifting, toggling, and checking flags.

1) Bitwise Operators in C

  • & AND
  • | OR
  • ^ XOR
  • ~ NOT (bitwise complement)
  • << Left shift
  • >> Right shift
#include <stdio.h>

int main() {
    unsigned int a = 5;  // 0101
    unsigned int b = 3;  // 0011

    printf("a & b = %u\n", a & b); // 0001 = 1
    printf("a | b = %u\n", a | b); // 0111 = 7
    printf("a ^ b = %u\n", a ^ b); // 0110 = 6
    printf("~a    = %u\n", (unsigned int)(~a));

    printf("a << 1 = %u\n", a << 1); // 1010 = 10
    printf("a >> 1 = %u\n", a >> 1); // 0010 = 2

    return 0;
}

2) Bit Masking (Check / Set / Clear / Toggle Bits)

  • Mask is a bit pattern used to isolate or modify specific bits.
  • Common operations:
    • Check bit: (n & mask) != 0
    • Set bit: n = n | mask
    • Clear bit: n = n & (~mask)
    • Toggle bit: n = n ^ mask
#include <stdio.h>

int main() {
    unsigned int n = 10;       // 1010
    unsigned int mask = 1u << 1; // bit 1 (0010)

    // Check bit 1
    if ((n & mask) != 0) {
        printf("Bit 1 is ON\n");
    } else {
        printf("Bit 1 is OFF\n");
    }

    // Set bit 0
    n = n | (1u << 0); // 1011
    printf("After set bit 0: %u\n", n);

    // Clear bit 3
    n = n & ~(1u << 3); // clears highest bit in 1011 -> 0011
    printf("After clear bit 3: %u\n", n);

    // Toggle bit 1
    n = n ^ (1u << 1);
    printf("After toggle bit 1: %u\n", n);

    return 0;
}

3) Shifts as Fast Multiply/Divide (Careful Use)

  • Left shift by k: n << k ≈ n × 2^k
  • Right shift by k: n >> k ≈ n ÷ 2^k (for unsigned / positive values)
#include <stdio.h>

int main() {
    unsigned int n = 6;

    printf("n = %u\n", n);
    printf("n*2 = %u\n", n << 1);
    printf("n/2 = %u\n", n >> 1);

    return 0;
}

4) Low-level Concepts (Supporting)

  • Endianness: byte order in memory (little-endian vs big-endian).
  • Flags: bits used to store multiple true/false states in one integer.
  • Bit-fields: store small-width values inside a struct (compiler dependent).
4.1) Flags Example
  • Store multiple ON/OFF settings in one integer.
#include <stdio.h>

#define FLAG_READ   (1u << 0)
#define FLAG_WRITE  (1u << 1)
#define FLAG_EXEC   (1u << 2)

int main() {
    unsigned int perm = 0;

    perm |= FLAG_READ;
    perm |= FLAG_WRITE;

    if (perm & FLAG_READ)  printf("READ allowed\n");
    if (perm & FLAG_WRITE) printf("WRITE allowed\n");
    if (perm & FLAG_EXEC)  printf("EXEC allowed\n");

    return 0;
}
4.2) Bit-field Example (Basic)
#include <stdio.h>

struct Status {
    unsigned int ready : 1;
    unsigned int error : 1;
    unsigned int mode  : 2; // 0-3
};

int main() {
    struct Status s = {1, 0, 2};

    printf("ready=%u error=%u mode=%u\n", s.ready, s.error, s.mode);
    return 0;
}

5) Quick Notes

  • Use unsigned types when doing bit operations to avoid sign issues.
  • Masking is the most common real-world use of bitwise operators.
  • Shifts are fast but should be used carefully (overflow/negative values).
  • Bitwise concepts are important for embedded and system-level programming.
⬅ Previous Next ➡