C Champs de bits
Le champ de bits du langage C est un membre spécial d'une structure qui nous permet de définir des membres en bits et de spécifier le nombre de bits qu'ils occupent.
Si la structure du programme contient plusieurs variables de commutation, c'est-à-dire que la valeur de la variable estTRUE/FALSE, comme suit :
struct
{
unsigned int widthValidated;
unsigned int heightValidated;
} status;
Cette structure nécessite 8 octets d'espace mémoire, mais en réalité nous ne stockons que 0 ou 1 dans chaque variable.
Dans ce cas, C offre un moyen de mieux utiliser l'espace mémoire : lorsque vous utilisez de telles variables dans une structure, vous pouvez définir la largeur de la variable, en indiquant au compilateur que vous n'utiliserez que ces bits.
Par exemple, la structure ci-dessus peut être réécrite comme suit :
struct
{
unsigned int widthValidated : 1;
unsigned int heightValidated : 1;
} status;
Maintenant, la variable status n'occupe que 4 bytes d'espace mémoire, mais seulement 2 bits sont utilisés pour stocker des valeurs.
Si 32 variables d'une largeur de 1 bit sont utilisées, la structure status n'occupe encore que 4 bytes ; mais une fois que 33 variables sont utilisées, le 33e bit sera alloué à l'unité mémoire suivante, et la structure entière commence à occuper 8 bytes.
Regardons l'exemple suivant pour comprendre ce concept :
Exemple
#include <string.h>
/* Définir une structure simple */
struct
{
unsigned int widthValidated;
unsigned int heightValidated;
} status1;
/* Définir une structure de champ de bits */
struct
{
unsigned int widthValidated : 1;
unsigned int heightValidated : 1;
} status2;
int main( )
{
printf( "Taille mémoire occupée par status1 : %zu\n", sizeof(status1));
printf( "Taille mémoire occupée par status2 : %zu\n", sizeof(status2));
return 0;
}
Lorsque le code ci-dessus est compilé et exécuté, il produit les résultats suivants :
Memory size occupied by status1 : 8 Memory size occupied by status2 : 4
Le tableau suivant résume les caractéristiques et l'utilisation des champs de bits :
| Fonctionnalités | Description |
|---|---|
| Spécification de largeur | Lors de la définition d'un champ de bits, vous pouvez spécifier la largeur du champ de bits du membre, c'est-à-dire le nombre de bits que le membre occupe. |
| Largeur maximale | La largeur d'un champ de bits ne peut pas dépasser la taille de son type de données, car le champ de bits doit tenir dans le type entier utilisé. |
| Types de données | En C standard, il doit s'agir deint、unsigned int、signed inttypes entiers, etc. L'utilisation d'autres types (tels que les énumérations) dépend de l'implémentation du compilateur et est moins portable. |
| Méthode de combinaison | Les champs de bits peuvent être utilisés seuls ou former une struct avec d'autres membres ordinaires. |
| Mode d'accès | Via l'opérateur point (.) ou l'opérateur flèche pour les pointeurs (->) accès, de la même manière que les membres ordinaires d'une structure. |
Déclaration de champ de bits
Certaines informations n'ont pas besoin d'occuper un octet complet lorsqu'elles sont stockées ; elles n'ont besoin que de quelques bits ou d'un seul bit. Par exemple, lors du stockage d'une valeur d'interrupteur, il n'y a que deux états, 0 et 1, donc 1 bit suffit. Pour économiser l'espace de stockage et simplifier le traitement, C fournit une structure de données appelée « champ de bits » ou « segment de bits ».
Le soi-disant « champ de bits » divise les bits d'un octet en plusieurs régions différentes et spécifie le nombre de bits dans chaque région. Chaque champ a un nom de champ, ce qui permet d'effectuer des opérations par nom de champ dans le programme. Ainsi, plusieurs objets différents peuvent être représentés par les champs de bits binaires d'un octet.
Un exemple typique : utiliser 1 bit binaire pour stocker une valeur d'interrupteur, qui n'a que deux états : 0 et 1.
Lire des formats de fichiers externes — peut lire des formats de fichiers non standard, tels que des entiers de 9 bits.
Définition des champs de bits et description des variables de champ de bits
La définition d'un champ de bits est similaire à une définition de structure, et sa forme est :
struct 位域结构名
{
位域列表
};
La liste des champs de bits a la forme suivante :
type [member_name] : width ;
Voici une description des éléments variables dans un champ de bits :
| élément | Description |
|---|---|
| type | Ne peut être que int (entier), unsigned int (entier non signé) ou signed int (entier signé), ce qui détermine comment la valeur du champ de bits est interprétée. |
| member_name | Le nom du champ de bits. |
| width | Le nombre de bits dans le champ de bits. La largeur doit être inférieure ou égale à la largeur en bits du type spécifié. |
Les variables avec une largeur prédéfinie sont appeléeschamps de bits. Les champs de bits peuvent stocker des nombres plus grands que 1 bit. Par exemple, si vous avez besoin d'une variable pour stocker des valeurs de 0 à 7, vous pouvez définir un champ de bits d'une largeur de 3 bits, comme suit :
{
unsigned int age : 3;
} Âge;
La définition de structure ci-dessus indique au compilateur C que la variable age n'utilisera que 3 bits pour stocker cette valeur.
Si la valeur assignée dépasse la plage que 3 bits peuvent représenter, la partie excédentaire subira unetroncature(voir exemple 2 ci-dessous).
int a:8;
int b:2;
int c:6;
}data;
Le code ci-dessus définit une variable nomméestruct bsstruct, data est une variable de structure de type bs, occupant un total de quatre octets.
Pour les champs de bits, leur largeur ne peut pas dépasser la taille de leur type de données ; la taille de int est généralement de 4 octets (32 bits).
Lorsque des champs de bits adjacents ont le même type, si la somme de leurs largeurs en bits ne dépasse pas la taille du type, le champ suivant sera stocké immédiatement à côté du champ précédent, jusqu'à ce qu'il ne puisse plus tenir.
Regardons un autre exemple :
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;
Le code ci-dessus définit une structure nommée packed_struct, qui contient six variables membres ; pack est une variable de structure de type packed_struct.
Ici, packed_struct contient 6 membres : quatre identifiants de 1 bit f1..f4, un type de 4 bits et un my_int de 9 bits.
Regardons l'exemple suivant :
Exemple 1
struct packed_struct {
unsigned int f1 : 1; // champ de bits de 1 bit
unsigned int f2 : 1; // champ de bits de 1 bit
unsigned int f3 : 1; // champ de bits de 1 bit
unsigned int f4 : 1; // champ de bits de 1 bit
unsigned int type : 4; // champ de bits de 4 bits
unsigned int my_int : 9; // champ de bits de 9 bits
};
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;
}
L'exemple ci-dessus définit une structure nommée packed_struct, qui contient plusieurs membres de champs de bits.
Dans la fonction main, une variable de structure pack de type packed_struct est créée, et une valeur est attribuée à chaque membre de champ de bits.
Ensuite, des instructions printf sont utilisées pour afficher la valeur de chaque membre de champ de bits.
La sortie est :
f1: 1 f2: 0 f3: 1 f4: 0 type: 7 my_int: 255
Exemple 2
#include <string.h>
struct
{
unsigned int age : 3;
} Âge;
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; // La représentation binaire est 1000, ce qui fait quatre bits, dépassant la plage autorisée
printf( "Age.age : %d\n", Age.age );
return 0;
}
Le code ci-dessus produira un avertissement de troncature lors de la compilation, et lorsqu'il est exécuté, il produit les résultats suivants :
Sizeof( Age ) : 4 Age.age : 4 Age.age : 7 Age.age : 0
Calculez le nombre d'octets :
Exemple
struct example1 {
int a : 4;
int b : 5;
int c : 7;
};
int main() {
struct example1 ex1;
printf("Taille de example1 : %zu octets\n", sizeof(ex1));
return 0;
}
Dans l'exemple ci-dessus, la structure example1 contient trois membres de champ de bits a, b et c, occupant respectivement 4 bits, 5 bits et 7 bits.
Utilisez l'opérateur sizeof pour calculer le nombre d'octets de la structure example1 et afficher le résultat :
Size of example1: 4 bytes
Concernant la définition des champs de bits, il y a les points suivants à expliquer :
-
Les membres de champ de bits tenteront d'être stockés dans la même unité de stockage. Si l'espace restant dans cette unité ne suffit pas à contenir le champ de bits suivant, le champ de bits sera stocké à partir de l'unité suivante.
Vous pouvez également faire démarrer intentionnellement un champ de bits à partir de l'unité suivante. Par exemple :
struct bs{ unsigned a:4; unsigned :4; /* 空域 */ unsigned b:4; /* 从下一单元开始存放 */ unsigned c:4; };Dans cette définition de champ de bits, a occupe 4 bits du premier octet, les 4 bits suivants sont remplis de 0 pour indiquer qu'ils ne sont pas utilisés, b commence au deuxième octet et occupe 4 bits, et c occupe 4 bits.
La largeur d'un champ de bits ne peut pas dépasser la longueur du type de données dont il dépend. Les variables membres ont toutes un type, et ce type limite la longueur maximale de la variable membre.:Les nombres suivants ne peuvent pas dépasser cette longueur.
-
Un champ de bits peut être un champ de bits sans nom, auquel cas il n'est utilisé que pour le remplissage ou l'ajustement de position. Les champs de bits sans nom ne peuvent pas être utilisés. Par exemple :
struct k{ int a:1; int :2; /* 该 2 位不能使用 */ int b:3; int c:2; };
D'après l'analyse ci-dessus, on peut voir qu'un champ de bits est essentiellement un type struct, sauf que ses membres sont alloués par bits.
Utilisation des champs de bits
L'utilisation des champs de bits est identique à l'utilisation des membres de struct ; sa forme générale est :
bit-field variable name.bit-field name bit-field variable name->bit-field name
Les champs de bits permettent une sortie dans divers formats.
Veuillez voir l'exemple suivant :
Exemple
int main(){
struct bs{
unsigned a:1;
unsigned b:3;
unsigned c:4;
} bit,*pbit;
bit.a=1; /* Affecter une valeur au champ de bits (notez que l'affectation ne doit pas dépasser la plage autorisée du champ de bits) */
bit.b=7; /* Affecter une valeur au champ de bits (notez que l'affectation ne doit pas dépasser la plage autorisée du champ de bits) */
bit.c=15; /* Affecter une valeur au champ de bits (notez que l'affectation ne doit pas dépasser la plage autorisée du champ de bits) */
printf("%d,%d,%d\n",bit.a,bit.b,bit.c); /* Afficher le contenu des trois champs au format entier */
pbit=&bit; /* Affecte l'adresse de la variable de champ de bits bit à la variable pointeur pbit */
pbit->a=0; /* Utiliser un pointeur pour réaffecter le champ de bits a à 0 */
pbit->b&=3; /* Utilise l'opérateur bit à bit composé "&=", équivalent à : pbit->b=pbit->b&3. La valeur d'origine du champ de bits b est 7, et le ET bit à bit avec 3 donne 3 (111&011=011, valeur décimale 3) */
pbit->c|=1; /* Utilise l'opérateur bit à bit composé "|=", équivalent à : pbit->c=pbit->c|1, et le résultat est 15 */
printf("%d,%d,%d\n",pbit->a,pbit->b,pbit->c); /* Affiche les valeurs de ces trois champs à l'aide de pointeurs */
return 0;
}
Lorsque le code ci-dessus est compilé et exécuté, il produit les résultats suivants :
1,7,15 0,3,15
Dans le programme d'exemple ci-dessus, une structure de champs de bits bs est définie, avec trois champs de bits a, b, c, ainsi qu'une variable bit de type bs et une variable pointeur pbit pointant vers le type bs.
Cela montre que les champs de bits peuvent aussi utiliser des pointeurs.
autres extensions