Mascheramento dei bit in C

Jinku Hu 12 ottobre 2023
  1. Usa la parola chiave struct per definire i dati della maschera di bit in C
  2. Usa struct combinato con union per definire i dati della maschera di bit in C
Mascheramento dei bit in C

Questo articolo illustrerà più metodi su come utilizzare il mascheramento dei bit in C.

Usa la parola chiave struct per definire i dati della maschera di bit in C

Le maschere di bit vengono solitamente utilizzate per le operazioni bit per bit per accedere o impostare singole sezioni delle strutture dati in stile campo di bit. D’altra parte, i campi di bit vengono utilizzati per archiviare i dati in modo efficiente e ridurre l’impronta di memoria. Inoltre, le operazioni bit per bit sono relativamente più veloci da eseguire nell’hardware piuttosto che nelle comuni operazioni aritmetiche. Nell’esempio seguente, dimostriamo l’implementazione del campo di bit utilizzando la parola chiave struct.

Si noti che questa è una notazione speciale per costruire l’oggetto in cui le regioni di bit specificate possono essere recuperate utilizzando l’operatore di accesso ai membri convenzionale. La struttura Bitfield memorizza un singolo intero senza segno che occupa 32 bit in memoria, ma è anche possibile accedervi in ​​3 diverse sezioni di dimensione: valori a 23 bit, 5 bit e 4 bit denominati year, day e month rispettivamente. Di conseguenza, il Bitfield rappresenta l’astrazione della data implementata in modo efficiente nella 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;
}

Produzione:

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

Usa struct combinato con union per definire i dati della maschera di bit in C

In alternativa, possiamo aggiungere la parola chiave union alla struttura precedente in modo che sia possibile accedere separatamente all’intero numero di 32 bit. Poiché l’accesso ai membri del campo di bit è più lento rispetto all’accesso al membro di struct, assegneremo il valore della data utilizzando le operazioni bit per bit al membro intero separato ydm.

Notare che i numeri decimali che rappresentano la data specificata sono logicamente in OR l’uno con l’altro, ma prima di ciò, i valori di day e month vengono spostati a sinistra di 23 e 28 posizioni, rispettivamente. Questi ultimi numeri vengono presi in base alle posizioni di bit corrispondenti che questi membri occupano nel campo di bit. Si noti che è ancora possibile accedere separatamente a ciascun membro quando necessario per stampare l’output.

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

Produzione:

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

Un altro tipico esempio di utilizzo della maschera di bit sono gli indirizzi IP in rete. Vale a dire, gli indirizzi IP vengono forniti con la maschera di rete, che determina a quale rete appartiene l’indirizzo specificato. Il calcolo dell’indirizzo di rete viene effettuato inserendo logicamente l’indirizzo IP e la relativa maschera di rete tramite AND. In questo caso, abbiamo definito il campo di bit struct per memorizzare separatamente l’indirizzo IP e la netmask. Si noti che l’operatore AND logico viene eseguito su tutti i valori a 32 bit, ma quando stampiamo gli indirizzi come le quattro sezioni a 8 bit, viene utilizzato l’operatore di accesso ai membri.

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

Produzione:

ip1: 10.127.5.1
net: 10.127.0.0
Autore: 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