Bitfeld in C

Abdul Mateen 12 Oktober 2023
  1. Bitfeld in C
  2. Bitfeldspeicherung in C
  3. Bitfeld mit dem Datentyp short in C
  4. Bitfeld mit mehreren Datentypen in C
  5. Abschluss
Bitfeld in C

In diesem Tutorial lernen wir das Bitfeld in der Sprache C kennen.

Wir werden die Diskussion vom Bitfeld aus beginnen. Als nächstes werden wir die Bitfeldspeicherung diskutieren, gefolgt von der Syntax des Bitfelds in der Sprache C.

Zuletzt sehen wir ein Bitfeld mit verschiedenen Datentypen, um den minimalen und maximalen Platzbedarf der Struktur mit einem darin enthaltenen Bitfeld zu verstehen.

Bitfeld in C

Ein Bitfeld in der Programmierung ist eine einzigartige Datenstruktur, die dem Programmierer hilft, Speicherplatz zu sparen. Das Bit-Feld erlaubt die Zuordnung von Speicher zu Strukturen in Bits.

Betrachten wir ein reines Schwarzweißbild mit nur zwei Farben Schwarzweiß. Wir müssen nur zwei Werte speichern: 0 oder 1.

Stellen Sie sich ein kleines 100x100-Bild vor, das den Bildschirm mit Tausenden von Pixeln in jeder Dimension vergleicht. Das Bild enthält zehntausend Pixel.

Bei Standarddatentypen haben Sie die Option des Datentyps unsigned char in der Sprache C, der nur ein Byte benötigt; Um jedoch ein reines Schwarz-Weiß-Bild zu speichern, benötigen Sie 10000 Byte Speicher.

Mit dem Bit-Feld können Sie acht Pixel in einem Byte (8 Bit in 1 Byte) speichern. Das bedeutet, dass Sie statt 10000 etwa 1250 Bytes benötigen.

Dies ist nur ein Beispiel; Das bedeutet nicht, dass Sie nur bei Bildern Platz sparen können. Bei einigen Prüfungen, bei denen Tausende von Kandidaten erscheinen, benötigen Sie nur ein Bit, um Pass/Fail-Informationen zu speichern; andernfalls besteht die Option darin, ein Byte für jeden Kandidaten zu verwenden.

Bitfeldspeicherung in C

Betrachten Sie die folgende Struktur, um eine Diskussion über die Speicherung von Bitfeldern zu beginnen:

struct {
  unsigned char is_married;
  unsigned char is_graduated;
} status0;

Diese Struktur benötigt zwei Bytes Speicherplatz; allerdings müssen wir in beiden Feldern entweder 0 oder 1 speichern. Kommen wir zu einer besseren Möglichkeit, Platz zu sparen.

Wir werden das Bitfeld von der Syntax bis zum Code im Detail sehen.

In der C-Sprache haben wir eine spezifische Syntax, um die Anzahl der Bits anzugeben, die für jede Variable erforderlich sind:

struct {
  type[variable_name] : size;  // Size will be in bits
}

Es ist wichtig zu beachten, dass diese Syntax mit Struktur verfügbar ist. Hier ist type ein beliebiger Datentyp wie int, char, short, unsigned char usw.

Sie kennen bereits rechtmäßige Variablennamen in der Sprache C. Der Doppelpunkt ist Teil der Syntax und wird zwischen dem Variablennamen und der Größe benötigt, und schließlich ist Größe die Anzahl der erforderlichen Bits.

Das nächste, was Sie überraschen könnte, ist die Größe der Struktur mit Bitgröße. Siehe folgenden Code:

#include <stdio.h>

struct {
  unsigned char is_married;
  unsigned char is_graduated;
} status0;

struct {
  unsigned char is_married : 1;
  unsigned char is_graduated : 1;
} status1;

int main() {
  printf("Memory size occupied by status1 : %ld bytes\n", sizeof(status0));
  printf("Memory size occupied by status1 : %ld  bytes\n", sizeof(status1));
  return 0;
}

Die Ausgabe ist:

Memory size occupied by status1 : 2 bytes
Memory size occupied by status1 : 1 bytes

In der Ausgabe benötigt die erste Struktur 2 Bytes (d. h. 1 Byte für jedes Feld), was sehr logisch ist. Der zweite Ausgang benötigt jedoch 1 Byte; Sie könnten 2 Bytes oder Bits erwarten.

Die Frage ist, warum ein Byte? Die Logik besteht darin, dass der Datentyp ein Byte pro Routinendefinition der C-Sprache verbraucht.

Durch die Angabe der Größe in Bits kann der Programmierer jedoch 7 weitere Felder mit jeweils 1 Bit deklarieren.

Die Gesamtbits sollten kleiner als gleich 8 Bits für 1 Byte bleiben. Andernfalls werden 2 Byte Speicher verbraucht.

Siehe die folgenden Codes:

#include <stdio.h>

struct {
  unsigned char a : 1;
  unsigned char b : 7;
} status0;

struct {
  unsigned char a : 1;
  unsigned char b : 1;
  unsigned char c : 1;
  unsigned char d : 1;
  unsigned char e : 1;
  unsigned char f : 1;
  unsigned char g : 1;
  unsigned char h : 1;
} status1;

int main() {
  printf("Memory size occupied by status1 : %ld\n", sizeof(status0));
  printf("Memory size occupied by status1 : %ld\n", sizeof(status1));
  return 0;
}

Die Ausgabe ist:

Memory size occupied by status1 : 1
Memory size occupied by status1 : 1

Schauen wir uns das nächste Beispiel an, wo die Anzahl der Bits erhöht wird:

#include <stdio.h>

struct {
  unsigned char a : 3;
  unsigned char b : 7;
  unsigned char c : 7;
} status0;

struct {
  unsigned char a : 1;
  unsigned char b : 1;
  unsigned char c : 1;
  unsigned char d : 1;
  unsigned char e : 1;
  unsigned char f : 1;
  unsigned char g : 1;
  unsigned char h : 1;
  unsigned char i : 1;
  unsigned char j : 1;
} status1;

int main() {
  printf("Memory size occupied by status1 : %ld\n", sizeof(status0));
  printf("Memory size occupied by status1 : %ld\n", sizeof(status1));
  return 0;
}

Die Ausgabe ist:

Memory size occupied by status1 : 3
Memory size occupied by status1 : 2

In der ersten Struktur sind die Gesamtbits 3 + 7 + 7 = 17, was größer als 16 Bits (2 Bytes) ist. Daher werden 3 Bytes verbraucht.

Dasselbe ist in der ersten Zeile der Ausgabe sichtbar.

In der 2. Struktur haben wir 10 Felder mit jeweils 1 Bit, was 10 Bit erfordert; daher verbraucht es zwei Bytes. Auch hier bestätigt die 2. Ausgabezeile das Konzept.

Bitfeld mit dem Datentyp short in C

Man könnte annehmen, dass ein unsigned char erforderlich ist, um das Bitfeld zu verwenden. Wir können das Bitfeld auch mit anderen Datentypen verwenden.

Hier betrachten wir den Datentyp short, um das Konzept des Bitfelds zu demonstrieren und besser in den Griff zu bekommen.

Betrachten Sie den folgenden Code:

#include <stdio.h>

struct {
  unsigned short a : 3;
} status0;

struct {
  unsigned short a : 3;
  unsigned short b : 9;
  unsigned short c : 4;
} status1;

int main() {
  printf("Memory size occupied by status1 : %ld\n", sizeof(status0));
  printf("Memory size occupied by status1 : %ld\n", sizeof(status1));
  return 0;
}

Die Ausgabe ist:

Memory size occupied by status1 : 2
Memory size occupied by status1 : 2

In beiden Strukturen beträgt der verbrauchte Speicher 2 Bytes, weil short 2 Bytes benötigt. Daher beträgt der minimal erforderliche Speicher 2 Byte.

Mehrere Felder können jedoch insgesamt 16 Bits verbrauchen (wie in der zweiten Struktur dargestellt), die Größe bleibt bei 2 Bytes.

Steigt die Anzahl der Bits von 16 an, werden die nächsten zwei Bytes des Datentyps short automatisch überdeckt und somit vier 4 verbraucht.

Schauen wir uns das folgende C-Programm an:

#include <stdio.h>

struct {
  unsigned short a : 6;
  unsigned short b : 6;
  unsigned short c : 7;
} status1;

int main() {
  printf("Memory size occupied by status1 : %ld\n", sizeof(status1));
  return 0;
}

Hier sind die Gesamtbits 6+6+7=19, also ist die Ausgabe:

Memory size occupied by status1 : 4

Beachten Sie, dass der Speicher Byte für Byte zunimmt, weil char einen Speicher von einem Byte hat; wohingegen im Fall von short der Speicher um zwei Bytes zunimmt, da short per Definition zwei Bytes Speicherplatz hat.

Bitfeld mit mehreren Datentypen in C

Jetzt ist es an der Zeit, die Speicheranforderungen für Bitfelder zu diskutieren, falls die Struktur zwei oder mehr Datentypen hat. In einem solchen Fall sind die mindestens erforderlichen Bytes der maximale Speicherplatz, der vom größten Datentyp in der Struktur benötigt wird.

Wenn eine Struktur beispielsweise Mitglieder von short und char hat, ist der größte Typ short und erfordert 2 Bytes; die gesamte Struktur erfordert mindestens zwei Bytes.

Im Fall von int & short ist int der größte Typ; daher erfordert die gesamte Struktur 4 Bytes. Lassen Sie uns das Konzept mit Hilfe des folgenden Codebeispiels demonstrieren:

#include <stdio.h>

struct {
  unsigned short a : 6;
  unsigned int b : 6;
} status1;

struct {
  unsigned long long a : 6;
  unsigned int b : 6;
  unsigned short c : 6;
} status2;

int main() {
  printf("Memory size occupied by status1 : %ld\n", sizeof(status1));
  printf("Memory size occupied by status1 : %ld\n", sizeof(status2));
  return 0;
}

Die Ausgabe ist:

Memory size occupied by status1 : 4 Memory size occupied by status1 : 8

In der ersten Struktur ist int der größte Datentyp; Daher zeigt die erste Ausgabezeile eine Strukturgröße von 4 Byte.

In der zweiten Struktur ist long long der dominierende Typ, daher zeigt die zweite Ausgabezeile acht Bytes Größe der Struktur.

Schließlich ist das Inkrement im Fall mehrerer Datengrößen einfach; Der Inkrementschritt ist die Größe, die gleich der Anzahl von Bytes im größten Strukturtyp ist.

Schauen wir uns zum besseren Verständnis den folgenden Code an:

#include <stdio.h>

struct {
  unsigned short a : 6;
  unsigned int b : 30;
  unsigned long long c : 50;
} status1;

int main() {
  printf("Memory size occupied by status1 : %ld\n", sizeof(status1));
  return 0;
}

Die Struktur hat 50+30+6=86 Bits, während 8 Bytes 64 Bits haben. Daher benötigte diese Struktur doppelten Platz, wie in der folgenden Ausgabe dargestellt:

Memory size occupied by status1 : 16

Wir brauchen 16 Bytes, die 8 + 8 Bytes sind.

Abschluss

Wir können Platz sparen, wenn wir in unserem Programm Mehrbitfelder verwenden. Wir können die Anzahl der Bits für eine Strukturelementvariable zum Zeitpunkt der Deklaration angeben.

Die Mindestgröße der Struktur ist die maximale Anzahl an Bytes, die für den größten Datentyp in der Struktur erforderlich sind.

Wenn die Einzel- oder Mehrfachfelder zusammen mehr Bits als die Größe des größten Typs in der Struktur verbrauchen, liegt der verbrauchte Speicher im Vielfachen der Größe des maximalen Speichertyps.

Verwandter Artikel - C Struct