Mascaramento de bits em C

Jinku Hu 12 outubro 2023
  1. Use a palavra-chave struct para definir dados de bitmask em C
  2. Use struct combinado com union para definir dados de bitmask em C
Mascaramento de bits em C

Este artigo demonstrará vários métodos sobre como usar o mascaramento de bits em C.

Use a palavra-chave struct para definir dados de bitmask em C

As máscaras de bits são geralmente usadas para operações bit a bit para acessar ou definir seções individuais das estruturas de dados de estilo de campo de bits. Por outro lado, os campos de bits são utilizados para armazenar dados de forma eficiente e reduzir o consumo de memória. Além disso, as operações bit a bit são relativamente mais rápidas de executar no hardware, em vez de operações aritméticas comuns. No exemplo a seguir, demonstramos a implementação do campo de bits usando a palavra-chave struct.

Observe que esta é uma notação especial para construir o objeto onde as regiões de bits fornecidas podem ser recuperadas usando o operador de acesso de membro convencional. A estrutura Bitfield armazena um único inteiro sem sinal ocupando 32 bits na memória, mas também pode ser acessado em 3 seções diferentes de tamanho - valores de 23 bits, 5 bits e 4 bits chamados de year, day e month respectivamente. Como resultado, o Bitfield representa a abstração de dados implementada de forma eficiente na memória.

#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;
}

Resultado:

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

Use struct combinado com union para definir dados de bitmask em C

Alternativamente, podemos adicionar a palavra-chave union à estrutura anterior para que seja possível acessar todo o número de 32 bits separadamente. Como o acesso aos membros do campo de bits é mais lento do que o acesso ao membro de struct, atribuiremos o valor de data usando as operações bit a bit ao membro inteiro ydm separado.

Observe que os números decimais que representam a data fornecida são logicamente OR-ed uns com os outros, mas antes disso, os valores day e month são deslocados para a esquerda em 23 e 28 casas, respectivamente. Os últimos números são obtidos com base nas posições de bits correspondentes que esses membros ocupam no campo de bits. Observe que cada membro ainda pode ser acessado separadamente quando necessário para imprimir a saída.

#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;
}

Resultado:

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

Outro exemplo típico de uso de bitmask são os endereços IP na rede. Ou seja, os endereços IP são fornecidos com a máscara de rede, que determina a qual rede pertence o endereço fornecido. O cálculo do endereço de rede é feito logicamente com o AND do endereço IP e sua máscara de rede. Neste caso, definimos o campo de bits struct para armazenar o endereço IP e a máscara de rede separadamente. Observe que o AND lógico é feito em todos os valores de 32 bits, mas quando imprimimos os endereços como as quatro seções de 8 bits, o operador de acesso de membro é usado.

#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;
}

Resultado:

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