DMarlon Studio

Lesson 14 · 14 of 20

Bitwise operators and flags · C

Store several permissions in one integer with bit flags in C: set with |, clear with & and ~, toggle with ^ and test with &.

C · Bitwise operators and flags in DMarlon Studio: the example's code and its output in the terminal

A flag is a bit with its own meaning. The enum gives each permission a different bit using shifts: 1 << 0 is 1, 1 << 1 is 2, 1 << 2 is 4 and 1 << 3 is 8. A single unsigned then holds all four permissions at once, which is how file permissions and the options of many APIs work.

`|` (OR) combines bits: READ | WRITE is 0011. |= adds a permission without touching the others. `&` with `~` removes one: ~WRITE has every bit set except the write bit, and ana &= ~WRITE turns it off. `^` (XOR) flips it: it turns ADMIN on the first time and would turn it off the second.

To test a permission, use &: guest & WRITE is 0 when the bit is off. ana & guest gives the bits both have, here only READ, which is 1.

show prints the bits from high to low with perms >> bit & 1: it shifts right until the wanted bit is last and keeps only that one. >> binds tighter than &, but when in doubt, add parentheses.

The last loop counts the bits set with a classic trick: v &= v - 1 clears the lowest 1, so the loop runs once per permission. Always use unsigned types for bit work: shifting negative numbers is not well defined.

Code · main.c

#include <stdio.h>// One bit per permission: 1, 2, 4, 8...enum { READ = 1 << 0, WRITE = 1 << 1, DELETE = 1 << 2, ADMIN = 1 << 3 };void show(const char *who, unsigned perms) {    printf("%-6s ", who);    for (int bit = 3; bit >= 0; bit--) putchar(perms >> bit & 1 ? '1' : '0');  // binary    printf(" %s%s%s%s\n", perms & READ ? " read" : "", perms & WRITE ? " write" : "",           perms & DELETE ? " delete" : "", perms & ADMIN ? " admin" : "");}int main(void) {    unsigned ana = READ | WRITE;  // | turns bits on    show("Ana", ana);    ana |= DELETE;               // add one permission    show("Ana", ana);    ana &= ~WRITE;               // & with ~ turns one bit off    show("Ana", ana);    ana ^= ADMIN;                // ^ toggles: on now, off if repeated    show("Ana", ana);    unsigned guest = READ;    printf("Guest can write? %s\n", (guest & WRITE) ? "yes" : "no");    printf("Common to both: %u\n", ana & guest);    int bits = 0;    for (unsigned v = ana; v; v &= v - 1) bits++;  // clears the lowest 1 each time    printf("Ana has %d permissions; 5 << 2 = %d, 40 >> 3 = %d\n", bits, 5 << 2, 40 >> 3);    return 0;}

Output · cc main.c -o main && ./main

Ana    0011  read write
Ana    0111  read write delete
Ana    0101  read delete
Ana    1101  read delete admin
Guest can write? no
Common to both: 1
Ana has 3 permissions; 5 << 2 = 20, 40 >> 3 = 5

Key points

  • x |= F sets, x &= ~F clears, x ^= F toggles.
  • x & F tests whether the bit is set.
  • 1 << n is bit n; x >> n shifts right.
  • Use unsigned types for bits.

Exercise

Add a SHARE = 1 << 4 flag, make show print five bits and write int has_all(unsigned perms, unsigned wanted) that says whether every permission in wanted is present.