Bit-Maskierung in C

Jinku Hu 12 Oktober 2023
  1. Verwenden Sie das Schlüsselwort struct, um Bitmasken-Daten in C zu definieren
  2. Verwendung von struct in Kombination mit union zur Definition von Bitmaskendaten in C
Bit-Maskierung in C

In diesem Artikel werden mehrere Methoden zur Verwendung von Bitmaskierung in C vorgestellt.

Verwenden Sie das Schlüsselwort struct, um Bitmasken-Daten in C zu definieren

Bitmasken werden normalerweise für bitweise Operationen verwendet, um auf einzelne Abschnitte von Datenstrukturen im Stil von Bitfeldern zuzugreifen oder diese zu setzen. Andererseits werden Bitfelder verwendet, um Daten effizient zu speichern und den Speicherbedarf zu reduzieren. Außerdem sind bitweise Operationen in der Hardware relativ schneller auszuführen als die üblichen arithmetischen Operationen. Im folgenden Beispiel demonstrieren wir die Implementierung des Bit-Feldes mit dem Schlüsselwort struct.

Beachten Sie, dass dies eine spezielle Notation ist, um das Objekt zu konstruieren, in dem die gegebenen Bitbereiche mit dem konventionellen Member-Zugriffsoperator abgerufen werden können. Die Struktur Bitfield speichert eine einzelne Ganzzahl unsigned, die 32 Bits im Speicher belegt, auf die aber auch in 3 verschiedenen Größenbereichen zugegriffen werden kann - 23-Bit-, 5-Bit- und 4-Bit-Werte, die jeweils als year, day und month bezeichnet werden. Im Ergebnis stellt das Bitfield die Abstraktion des Datums dar, die effizient im Speicher implementiert ist.

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

Ausgabe:

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

Verwendung von struct in Kombination mit union zur Definition von Bitmaskendaten in C

Alternativ können wir die bisherige Struktur um das Schlüsselwort union ergänzen, so dass ein separater Zugriff auf die gesamte 32-Bit-Zahl möglich ist. Da der Zugriff auf die Bitfeld-Mitglieder langsamer ist als der Zugriff auf das Mitglied von struct, werden wir den Datumswert mit Hilfe der bitweisen Operationen dem separaten Integer-Mitglied ydm zuweisen.

Beachten Sie, dass die Dezimalzahlen, die das angegebene Datum repräsentieren, logisch miteinander ODER-verknüpft werden, aber vorher werden die Werte für day und month um 23 bzw. 28 Stellen nach links verschoben. Die letztgenannten Zahlen werden auf der Grundlage der entsprechenden Bitpositionen, die diese Mitglieder im Bitfeld einnehmen, genommen. Beachten Sie, dass auf jedes Mitglied weiterhin separat zugegriffen werden kann, wenn es für die Ausgabe benötigt wird.

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

Ausgabe:

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

Ein weiteres typisches Beispiel für die Verwendung von Bitmasken sind IP-Adressen in Netzwerken. IP-Adressen werden nämlich mit der Netzwerkmaske versehen, die bestimmt, zu welchem Netzwerk die jeweilige Adresse gehört. Die Berechnung der Netzwerkadresse erfolgt durch logische UND-Verknüpfung der IP-Adresse und ihrer Netzwerkmaske. In diesem Fall haben wir das Bitfeld struct definiert, um die IP-Adresse und die Netzmaske getrennt zu speichern. Beachten Sie, dass die logische UND-Verknüpfung mit den gesamten 32-Bit-Werten durchgeführt wird, aber wenn wir die Adressen als die vier 8-Bit-Abschnitte ausgeben, wird der Elementzugriffsoperator verwendet.

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

Ausgabe:

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