C Bitfelder
Ein Bitfeld in der Sprache C ist ein spezielles Strukturmitglied, mit dem wir Mitglieder bitweise definieren und die Anzahl der Bits angeben können, die sie belegen.
Wenn die Struktur des Programms mehrere Schaltervariablen enthält, d. h., der Variablenwert istTRUE/FALSE, wie folgt:
struct
{
unsigned int widthValidated;
unsigned int heightValidated;
} status;
Diese Struktur benötigt 8 Bytes Speicherplatz, aber in Wirklichkeit speichern wir in jeder Variablen nur 0 oder 1.
In diesem Fall bietet C eine Möglichkeit, den Speicherplatz besser zu nutzen: Wenn Sie solche Variablen in einer Struktur verwenden, können Sie die Breite der Variable definieren und dem Compiler mitteilen, dass Sie nur diese Bits verwenden werden.
Zum Beispiel kann die obige Struktur wie folgt umgeschrieben werden:
struct
{
unsigned int widthValidated : 1;
unsigned int heightValidated : 1;
} status;
Nun belegt die status-Variable nur 4 Bytes Speicherplatz, aber es werden nur 2 Bits zum Speichern von Werten verwendet.
Wenn 32 Variablen mit einer Breite von 1 Bit verwendet werden, belegt die status-Struktur weiterhin nur 4 Bytes; sobald jedoch 33 Variablen verwendet werden, wird das 33. Bit der nächsten Speichereinheit zugewiesen, und die gesamte Struktur beginnt, 8 Bytes zu belegen.
Schauen wir uns das folgende Beispiel an, um dieses Konzept zu verstehen:
Beispiel
#include <string.h>
/* Eine einfache Struktur definieren */
struct
{
unsigned int widthValidated;
unsigned int heightValidated;
} status1;
/* Eine Bitfeld-Struktur definieren */
struct
{
unsigned int widthValidated : 1;
unsigned int heightValidated : 1;
} status2;
int main( )
{
printf( "Von status1 belegter Speicherplatz : %zu\n", sizeof(status1));
printf( "Belegte Speichergröße von status2 : %zu\n", sizeof(status2));
return 0;
}
Wenn der obige Code kompiliert und ausgeführt wird, liefert er die folgenden Ergebnisse:
Memory size occupied by status1 : 8 Memory size occupied by status2 : 4
Die folgende Tabelle fasst die Eigenschaften und die Verwendung von Bitfeldern zusammen:
| Funktionen | Beschreibung |
|---|---|
| Breitenangabe | Beim Definieren eines Bitfelds können Sie die Bitfeldbreite des Members angeben, d. h. die Anzahl der Bits, die das Member belegt. |
| Maximale Breite | Die Breite eines Bitfelds darf die Größe seines Datentyps nicht überschreiten, da das Bitfeld in den verwendeten Integer-Typ passen muss. |
| Datentypen | In Standard-C sollte es seinint、unsigned int、signed intInteger-Typen usw. Die Verwendung anderer Typen (wie z. B. Enums) hängt von der Compiler-Implementierung ab und ist weniger portabel. |
| Kombinationsmethode | Bitfelder können allein verwendet werden oder zusammen mit anderen gewöhnlichen Members eine Struktur bilden. |
| Zugriffsmethode | Durch den Punktoperator (.) oder den Pfeiloperator für Zeiger (->) Zugriff, in der gleichen Weise wie auf gewöhnliche Strukturmitglieder. |
Bitfeld-Deklaration
Manche Informationen müssen bei der Speicherung nicht ein volles Byte belegen; sie benötigen nur wenige Bits oder ein Bit. Wenn man beispielsweise einen Schalterwert speichert, gibt es nur zwei Zustände, 0 und 1, daher reicht 1 Bit aus. Um Speicherplatz zu sparen und die Verarbeitung zu vereinfachen, bietet C eine Datenstruktur namens „Bitfeld“ oder „Bitsegment“.
Das sogenannte „Bitfeld“ unterteilt die Bits in einem Byte in mehrere verschiedene Bereiche und gibt die Anzahl der Bits in jedem Bereich an. Jedes Feld hat einen Feldnamen, sodass im Programm Operationen über den Feldnamen ausgeführt werden können. Auf diese Weise können mehrere verschiedene Objekte durch die binären Bitfelder eines Bytes dargestellt werden.
Ein typisches Beispiel: Mit 1 Binärbit wird ein Schalterwert gespeichert, der nur zwei Zustände hat: 0 und 1.
Externe Dateiformate lesen – kann nicht standardmäßige Dateiformate lesen, wie z. B. 9-Bit-Ganzzahlen.
Definition von Bitfeldern und Beschreibung von Bitfeldvariablen
Die Definition eines Bitfelds ähnelt der Definition einer Struktur, und ihre Form ist:
struct 位域结构名
{
位域列表
};
Die Bitfeldliste hat die folgende Form:
type [member_name] : width ;
Das Folgende ist eine Beschreibung der variablen Elemente in einem Bitfeld:
| element | Beschreibung |
|---|---|
| type | Kann nur int (Ganzzahl), unsigned int (vorzeichenlose Ganzzahl) oder signed int (vorzeichenbehaftete Ganzzahl) sein, was bestimmt, wie der Wert des Bitfelds interpretiert wird. |
| member_name | Der Name des Bitfelds. |
| width | Die Anzahl der Bits im Bitfeld. Die Breite muss kleiner oder gleich der Bitbreite des angegebenen Typs sein. |
Variablen mit einer vordefinierten Breite heißenBitfelder. Bitfelder können Zahlen speichern, die größer als 1 Bit sind. Wenn Sie beispielsweise eine Variable benötigen, um Werte von 0 bis 7 zu speichern, können Sie ein Bitfeld mit einer Breite von 3 Bits wie folgt definieren:
{
unsigned int age : 3;
} Alter;
Die obige struct-Definition teilt dem C-Compiler mit, dass die Variable age nur 3 Bits verwendet, um diesen Wert zu speichern.
Wenn der zugewiesene Wert den Bereich überschreitet, den 3 Bits darstellen können, wird der überschüssige Teilabgeschnitten(siehe Beispiel 2 unten).
int a:8;
int b:2;
int c:6;
}data;
Der obige Code definiert eine Variable namensstruct bsstruct, wobei data eine Strukturvariable vom Typ bs ist und insgesamt vier Bytes belegt.
Bei Bitfeldern darf ihre Breite die Größe ihres Datentyps nicht überschreiten; die Größe von int beträgt üblicherweise 4 Bytes (32 Bits).
Wenn benachbarte Bitfelder denselben Typ haben und die Summe ihrer Bitbreiten die Größe des Typs nicht überschreitet, wird das spätere Feld unmittelbar neben dem vorherigen Feld gespeichert, bis es nicht mehr passt.
Sehen wir uns ein weiteres Beispiel an:
unsigned int f1:1;
unsigned int f2:1;
unsigned int f3:1;
unsigned int f4:1;
unsigned int type:4;
unsigned int my_int:9;
} pack;
Der obige Code definiert eine Struktur namens packed_struct, die sechs Mitgliedsvariablen enthält; pack ist eine Strukturvariable vom Typ packed_struct.
Hier enthält packed_struct 6 Mitglieder: vier 1-Bit-Bezeichner f1..f4, einen 4-Bit-Typ und ein 9-Bit-my_int.
Schauen wir uns das folgende Beispiel an:
Beispiel 1
struct packed_struct {
unsigned int f1 : 1; // 1-Bit-Bitfeld
unsigned int f2 : 1; // 1-Bit-Bitfeld
unsigned int f3 : 1; // 1-Bit-Bitfeld
unsigned int f4 : 1; // 1-Bit-Bitfeld
unsigned int type : 4; // 4-Bit-Bitfeld
unsigned int my_int : 9; // 9-Bit-Bitfeld
};
int main() {
struct packed_struct pack;
pack.f1 = 1;
pack.f2 = 0;
pack.f3 = 1;
pack.f4 = 0;
pack.type = 7;
pack.my_int = 255;
printf("f1: %u\n", pack.f1);
printf("f2: %u\n", pack.f2);
printf("f3: %u\n", pack.f3);
printf("f4: %u\n", pack.f4);
printf("type: %u\n", pack.type);
printf("my_int: %u\n", pack.my_int);
return 0;
}
Das obige Beispiel definiert eine Struktur namens packed_struct, die mehrere Bitfeld-Mitglieder enthält.
In der main-Funktion wird eine Strukturvariable pack vom Typ packed_struct erstellt, und jedem Bitfeld-Mitglied wird ein Wert zugewiesen.
Dann werden printf-Anweisungen verwendet, um den Wert jedes Bitfeld-Mitglieds auszugeben.
Die Ausgabe ist:
f1: 1 f2: 0 f3: 1 f4: 0 type: 7 my_int: 255
Beispiel 2
#include <string.h>
struct
{
unsigned int age : 3;
} Alter;
int main( )
{
Age.age = 4;
printf( "Sizeof( Age ) : %zu\n", sizeof(Age) );
printf( "Age.age : %d\n", Age.age );
Age.age = 7;
printf( "Age.age : %d\n", Age.age );
Age.age = 8; // Binäre Darstellung ist 1000, die vier Bits hat und den zulässigen Bereich überschreitet
printf( "Age.age : %d\n", Age.age );
return 0;
}
Der obige Code erzeugt während der Kompilierung eine Warnung vor Abschneiden, und bei der Ausführung erzeugt er die folgenden Ergebnisse:
Sizeof( Age ) : 4 Age.age : 4 Age.age : 7 Age.age : 0
Berechnen Sie die Anzahl der Bytes:
Beispiel
struct example1 {
int a : 4;
int b : 5;
int c : 7;
};
int main() {
struct example1 ex1;
printf("Größe von example1: %zu bytes\n", sizeof(ex1));
return 0;
}
Im obigen Beispiel enthält die Struktur example1 drei Bitfeld-Mitglieder a, b und c, die 4 Bits, 5 Bits bzw. 7 Bits belegen.
Verwenden Sie den sizeof-Operator, um die Anzahl der Bytes der Struktur example1 zu berechnen und das Ergebnis auszugeben:
Size of example1: 4 bytes
Bezüglich der Definition von Bitfeldern sind folgende Punkte zu erklären:
-
Bitfeld-Mitglieder werden versuchen, in derselben Speichereinheit gespeichert zu werden. Wenn der verbleibende Platz in dieser Einheit nicht ausreicht, um das nächste Bitfeld aufzunehmen, wird das Bitfeld ab der nächsten Einheit gespeichert.
Sie können ein Bitfeld auch absichtlich von der nächsten Einheit an beginnen lassen. Zum Beispiel:
struct bs{ unsigned a:4; unsigned :4; /* 空域 */ unsigned b:4; /* 从下一单元开始存放 */ unsigned c:4; };In dieser Bitfeld-Definition belegt a 4 Bits des ersten Bytes, die nächsten 4 Bits werden mit 0 gefüllt, um anzuzeigen, dass sie unbenutzt sind, b beginnt beim zweiten Byte und belegt 4 Bits, und c belegt 4 Bits.
Die Breite eines Bitfelds darf die Länge des Datentyps, von dem es abhängt, nicht überschreiten. Alle Membervariablen haben Typen, und dieser Typ begrenzt die maximale Länge der Membervariable.:Die folgenden Zahlen dürfen diese Länge nicht überschreiten.
-
Ein Bitfeld kann ein unbenanntes Bitfeld sein; in diesem Fall wird es nur zum Auffüllen oder Anpassen der Position verwendet. Unbenannte Bitfelder können nicht verwendet werden. Zum Beispiel:
struct k{ int a:1; int :2; /* 该 2 位不能使用 */ int b:3; int c:2; };
Aus der obigen Analyse geht hervor, dass ein Bitfeld im Wesentlichen ein Strukturtyp ist, außer dass seine Member bitweise allokiert werden.
Verwendung von Bitfeldern
Die Verwendung von Bitfeldern entspricht der Verwendung von Struct-Membern; ihre allgemeine Form ist:
bit-field variable name.bit-field name bit-field variable name->bit-field name
Bitfelder ermöglichen die Ausgabe in verschiedenen Formaten.
Siehe das folgende Beispiel:
Beispiel
int main(){
struct bs{
unsigned a:1;
unsigned b:3;
unsigned c:4;
} bit,*pbit;
bit.a=1; /* Weisen Sie dem Bitfeld einen Wert zu (beachten Sie, dass die Zuweisung den zulässigen Bereich des Bitfelds nicht überschreiten darf) */
bit.b=7; /* Weisen Sie dem Bitfeld einen Wert zu (beachten Sie, dass die Zuweisung den zulässigen Bereich des Bitfelds nicht überschreiten darf) */
bit.c=15; /* Weisen Sie dem Bitfeld einen Wert zu (beachten Sie, dass die Zuweisung den zulässigen Bereich des Bitfelds nicht überschreiten darf) */
printf("%d,%d,%d\n",bit.a,bit.b,bit.c); /* Den Inhalt der drei Felder im Integer-Format ausgeben */
pbit=&bit; /* Weist die Adresse der Bitfeldvariable bit der Zeigervariable pbit zu */
pbit->a=0; /* Verwende einen Zeiger, um das Bitfeld a auf 0 neu zuzuweisen */
pbit->b&=3; /* Verwendet den zusammengesetzten bitweisen Operator "&=", äquivalent zu: pbit->b=pbit->b&3. Der ursprüngliche Wert des Bitfelds b ist 7, und das bitweise UND mit 3 ergibt 3 (111&011=011, Dezimalwert 3) */
pbit->c|=1; /* Verwendet den zusammengesetzten bitweisen Operator "|=", äquivalent zu: pbit->c=pbit->c|1, und das Ergebnis ist 15 */
printf("%d,%d,%d\n",pbit->a,pbit->b,pbit->c); /* Gib die Werte dieser drei Felder mithilfe von Zeigern aus */
return 0;
}
Wenn der obige Code kompiliert und ausgeführt wird, liefert er die folgenden Ergebnisse:
1,7,15 0,3,15
Im obigen Beispielprogramm wird eine Bitfeldstruktur bs definiert, mit drei Bitfeldern a, b, c sowie einer Variablen bit vom Typ bs und einer Zeigervariablen pbit, die auf den Typ bs zeigt.
Dies zeigt, dass Bitfelder auch Zeiger verwenden können.
Weitere Erweiterungen