DMarlon Studio

Lección 14 · 14 de 20

Operadores de bits y banderas · C

Guarde varios permisos en un solo entero con banderas de bits en C: activar con |, quitar con & y ~, alternar con ^ y comprobar con &.

C · Operadores de bits y banderas en DMarlon Studio: el código del ejemplo y su salida en la terminal

Una bandera es un bit con significado propio. El enum da a cada permiso un bit distinto con desplazamientos: 1 << 0 es 1, 1 << 1 es 2, 1 << 2 es 4 y 1 << 3 es 8. Así un solo unsigned guarda los cuatro permisos a la vez, que es como lo hacen los permisos de archivos o las opciones de muchas API.

`|` (O) junta bits: READ | WRITE es 0011. Con |= se añade un permiso sin tocar los demás. `&` con `~` quita uno: ~WRITE tiene todos los bits a 1 menos el de escribir, y ana &= ~WRITE lo apaga. `^` (O exclusivo) lo invierte: activa ADMIN la primera vez y lo desactivaría la segunda.

Para comprobar un permiso se usa &: guest & WRITE es 0 si el bit está apagado. ana & guest da los bits que tienen los dos, aquí solo READ, que vale 1.

show escribe los bits de mayor a menor con perms >> bit & 1: desplaza a la derecha hasta dejar el bit buscado en la última posición y se queda solo con él. >> tiene más prioridad que &, pero ante la duda conviene poner paréntesis.

El último bucle cuenta los bits a 1 con un truco clásico: v &= v - 1 apaga el 1 más bajo, así que el bucle da tantas vueltas como permisos hay. Use siempre tipos unsigned para trabajar con bits: desplazar números negativos no está bien definido.

Código · 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;}

Salida · 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

Para recordar

  • x |= F activa, x &= ~F desactiva, x ^= F alterna.
  • x & F comprueba si el bit está activo.
  • 1 << n es el bit n; x >> n desplaza a la derecha.
  • Para bits, use tipos unsigned.

Ejercicio

Añada la bandera SHARE = 1 << 4, cambie show para que escriba cinco bits y escriba una función int has_all(unsigned perms, unsigned wanted) que diga si están todos los permisos de wanted.