Máscaras de bit

Con las máscaras de bit es posible proporcionar a las funciones una interfaz para pasar múltiples parámetros booleanos de una manera eficiente y fácil de documentar. También hablo del operador desplazamiento.

Cuando trabajamos con funciones que requieren múltiples opciones booleanas, es común encontrarnos con un problema: pasar muchos parámetros que solo pueden ser verdadero o falso. Si usamos variables como char o int para cada opción, estamos desperdiciando bits, ya que cada variable ocupa varios bits aunque solo necesitemos uno para representar dos estados. Además, manejar muchas variables booleanas como parámetros puede hacer que las llamadas a funciones sean confusas e inmantenibles, especialmente cuando el orden o la cantidad de parámetros crece.

Para solucionar esto, podemos usar máscaras de bits, una técnica que nos permite representar múltiples opciones booleanas en un solo valor numérico, aprovechando cada bit para una opción distinta. Por ejemplo, si tenemos ocho opciones, podemos usar un char de 8 bits y asignar a cada bit una opción diferente: azul, verde, rojo, naranja, amarillo, pardo, blanco y negro. Así, cada color corresponde a un bit específico dentro del char.

Para definir estas máscaras, podemos asignar a cada color un valor con un solo bit encendido en la posición correspondiente. Por ejemplo, el bit 7 para azul, el 6 para verde, y así sucesivamente hasta el bit 0 para negro. Esto se puede hacer fácilmente usando el operador de desplazamiento a la izquierda (<<) en C, que mueve el bit 1 tantas posiciones como necesitemos. Así, el negro sería 1 << 0, el blanco 1 << 1, el pardo 1 << 2, y así sucesivamente hasta el azul 1 << 7.

Con estas definiciones, podemos combinar varias opciones en un solo valor usando el operador OR bit a bit (|). Por ejemplo, si queremos activar azul, verde y pardo, hacemos:

int colores = AZUL | VERDE | PARDO;

Esto genera un valor donde solo están encendidos los bits correspondientes a esos colores. Lo interesante es que el orden en que combinamos las opciones no importa, ya que el operador OR es conmutativo.

Para comprobar si una opción está activa dentro de una máscara, usamos el operador AND bit a bit (&). Por ejemplo, para saber si el color amarillo está activo en colores, hacemos:

if (colores & AMARILLO) {
    printf("Amarillo está activo\n");
}

Si el resultado es distinto de cero, significa que el bit correspondiente está encendido.

También podemos apagar bits específicos usando el operador AND junto con el complemento bit a bit (~). Por ejemplo, para apagar el bit verde en colores, hacemos:

colores &= ~VERDE;

Esto mantiene todos los bits igual excepto el de verde, que se pone a cero.

Un detalle importante al usar el complemento es el orden de las operaciones. El operador complemento tiene mayor prioridad que el desplazamiento, por lo que debemos usar paréntesis para asegurarnos de que primero se haga el desplazamiento y luego el complemento:

#define VERDE (1 << 6)
colores &= ~(VERDE);

De esta forma, evitamos errores donde se complementa primero el 1 y luego se desplaza, lo que daría un resultado incorrecto.

En resumen, las máscaras de bits nos permiten manejar múltiples opciones booleanas de forma eficiente y clara, usando un solo parámetro para representar muchas opciones y facilitando la manipulación y comprobación de cada una mediante operadores bit a bit. Esto es especialmente útil en librerías y entornos donde se manejan muchas opciones configurables, como en gráficos o interfaces de usuario.

Lista de reproducción
  1. 1
    Instalar CodeBlocks
    15 minutos
  2. 2
    Funciones y hola mundo
    17 minutos
  3. 3
    Variables y tipos de datos
    17 minutos
  4. 4
    Condicionales y operadores lógicos
    16 minutos
  5. 5
    Bucles
    11 minutos
  6. 6
    Punteros
    12 minutos
  7. 7
    Arrays
    14 minutos
  8. 8
    Estructuras
    12 minutos
  9. 9
    Otras construcciones de C
    9 minutos
  10. 10
    Memoria dinámica
    8 minutos
  11. 11
    El preprocesador (parte 1)
    10 minutos
  12. 12
    El preprocesador (parte 2)
    9 minutos
  13. 13
    Archivos de cabecera y múltiples .c (parte 1)
    8 minutos
  14. 14
    Archivos de cabecera y múltiples .c (parte 2)
    9 minutos
  15. 15
    C desde la línea de comandos (parte 1)
    8 minutos
  16. 16
    C desde la línea de comandos (parte 2)
    9 minutos
  17. 17
    Break y continue
    10 minutos
  18. 18
    Goto
    13 minutos
  19. 19
    Manipulación de bits
    15 minutos
  20. 20
    Máscaras de bit
    19 minutos
  21. 21
    Archivos (1): fopen y fclose
    13 minutos
  22. 22
    Archivos (2): leer con fgetc
    9 minutos
  23. 23
    Archivos (3): fseek y ftell
    11 minutos
  24. 24
    Archivos (4): leer con fgets
    9 minutos
  25. 25
    Archivos (5): fputc y fputs
    7 minutos
  26. 26
    Archivos (6): volcar en archivos con fwrite
    10 minutos
  27. 27
    Archivos (7): fread, fwrite y los arrays
    10 minutos
  28. 28
    Archivos (8): entrada estándar y salida estándar
    9 minutos
  29. 29
    Archivos (9): buffers
    14 minutos
  30. 30
    Archivos (y 10): otras funciones útiles con archivos
    5 minutos
  31. 31
    printf (1)
    18 minutos
  32. 32
    printf (parte 2)
    12 minutos
  33. 33
    scanf (parte 1)
    17 minutos
  34. 34
    scanf (parte 2)
    17 minutos
  35. 35
    fprintf, sprintf y snprintf
    8 minutos
  36. 36
    Tipos de datos opacos
    13 minutos
  37. 37
    Bibliotecas estáticas
    13 minutos
  38. 38
    Bibliotecas dinámicas
    15 minutos
  39. 39
    Más flags: i mayúscula (include), wall, werror, pedantic...
    12 minutos
  40. 40
    pkg-config
    12 minutos
  41. 41
    Make
    17 minutos
  42. 42
    GDB
    21 minutos
  43. 43
    Variables globales
    6 minutos
  44. 44
    extern
    9 minutos
  45. 45
    Funciones variádicas
    12 minutos
  46. 46
    El optimizador de GCC y la opción -O
    12 minutos
  47. 47
    Volatile
    6 minutos