Enmascaramiento de bits en C

Jinku Hu 12 octubre 2023
  1. Usar la palabra clave struct para definir datos de máscara de bits en C
  2. Uso de struct combinado con union para definir datos de máscara de bits en C
Enmascaramiento de bits en C

Este artículo demostrará múltiples métodos sobre cómo usar el enmascaramiento de bits en C.

Usar la palabra clave struct para definir datos de máscara de bits en C

Las máscaras de bits son usadas usualmente para operaciones bitwise para acceder o establecer secciones individuales de las estructuras de datos estilo campo de bits. Por otro lado, los campos de bits se utilizan para almacenar datos de manera eficiente y reducir la huella de memoria. Además, las operaciones a nivel de bits son relativamente más rápidas de ejecutar en el hardware que las operaciones aritméticas comunes. En el siguiente ejemplo, demostramos la implementación del campo de bits utilizando la palabra clave struct.

Tenga en cuenta que se trata de una notación especial para construir el objeto donde las regiones de bits dadas pueden ser recuperadas utilizando el operador de acceso a miembros convencional. La estructura Bitfield almacena un único entero sin signo que ocupa 32 bits en memoria, pero también se puede acceder a él en 3 secciones diferentes de tamaño - valores de 23 bits, 5 bits y 4 bits denominados year, dau y month respectivamente. Como resultado, el Bitfield representa la abstracción de la fecha implementada eficientemente en la memoria.

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

struct {
  uint32_t year : 23;
  uint32_t day : 5;
  uint32_t month : 4;
} typedef Bitfield;

int main() {
  Bitfield date = {2020, 13, 12};

  printf("sizeof Bitfield: %lu bytes\n", sizeof(date));
  printf("date: %d/%d/%d \n", date.day, date.month, date.year);

  return EXIT_SUCCESS;
}

Producción :

sizeof Bitfield: 4 bytes
date: 13/12/2020

Uso de struct combinado con union para definir datos de máscara de bits en C

Alternativamente, podemos añadir la palabra clave union a la estructura anterior para que sea posible acceder a todo el número de 32 bits por separado. Dado que acceder a los miembros del campo de bits es más lento que acceder al miembro de struct, asignaremos el valor de la fecha utilizando las operaciones bitwise al miembro entero separado ydm.

Tenga en cuenta que los números decimales que representan la fecha dada son lógicamente OR-ed con los demás, pero antes de eso, el day y month valores se desplazan a la izquierda por 23 y 28 lugares, respectivamente. Estos últimos números se toman en base a las correspondientes posiciones de bits que estos miembros ocupan en el campo de bits. Observe que se puede acceder a cada miembro por separado cuando sea necesario para imprimir la salida.

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

union {
  struct {
    uint32_t year : 23;
    uint32_t day : 5;
    uint32_t month : 4;
  };
  uint32_t ydm;
} typedef BitfieldFast;

int main() {
  BitfieldFast date_f;
  date_f.ydm = 2020 | (13 << 23) | (12 << 28);

  printf("sizeof BitfieldFast: %lu bytes\n", sizeof(date_f));
  printf("date_f: %d/%d/%d \n", date_f.day, date_f.month, date_f.year);

  return EXIT_SUCCESS;
}

Producción :

sizeof BitfieldFast: 4 bytes
date_f: 13/12/2020

Otro ejemplo típico de uso de máscaras de bits son las direcciones IP en las redes. En concreto, las direcciones IP se proporcionan con la máscara de red, que determina a qué red pertenece la dirección dada. El cálculo de la dirección de red se hace sumando lógicamente la dirección IP y su máscara de red. En este caso, definimos el campo de bits struct para almacenar la dirección IP y la máscara de red por separado. Tenga en cuenta que el AND lógico se realiza sobre los valores completos de 32 bits, pero cuando imprimimos las direcciones como las cuatro secciones de 8 bits, se utiliza el operador de acceso al miembro.

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

union {
  struct {
    uint8_t first : 8;
    uint8_t second : 8;
    uint8_t third : 8;
    uint8_t fourth : 8;
  };
  uint32_t ip;
} typedef IPAddress;

int main() {
  IPAddress ip1 = {10, 127, 5, 1};
  IPAddress mask = {255, 255, 240, 0};
  printf("ip1: %d.%d.%d.%d\n", ip1.first, ip1.second, ip1.third, ip1.fourth);
  ip1.ip = ip1.ip & mask.ip;
  printf("net: %d.%d.%d.%d\n", ip1.first, ip1.second, ip1.third, ip1.fourth);

  return EXIT_SUCCESS;
}

Producción :

ip1: 10.127.5.1
net: 10.127.0.0
Autor: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.

LinkedIn Facebook