Article de reference

Champ de bits

Un champ de bits est une structure de données qui associe un ou plusieurs bits adjacents alloués à des fins spécifiques, de sorte que n'importe quel bit ou groupe de bits au sei...

Un champ de bits est une structure de données qui associe un ou plusieurs bits adjacents alloués à des fins spécifiques, de sorte que n'importe quel bit ou groupe de bits au sein de la structure puisse être défini ou examiné. Un champ de bits est le plus souvent utilisé pour représenter des types entiers de largeur de bits connue et fixe, tels que les booléens à un seul bit .

La signification des bits individuels au sein du champ est déterminée par le programmeur ; par exemple, le premier bit d’un champ de bits (situé à l’ adresse de base du champ ) est parfois utilisé pour déterminer l’état d’un attribut particulier associé au champ de bits.

Dans les processeurs et autres dispositifs logiques, des ensembles de champs binaires appelés drapeaux sont couramment utilisés pour contrôler ou indiquer le résultat d'opérations particulières. Les processeurs possèdent un registre d'état composé de drapeaux. Par exemple, si le résultat d'une addition ne peut être représenté dans la destination, un dépassement de capacité arithmétique est déclenché. Les drapeaux peuvent servir à déterminer les opérations suivantes, telles que les instructions de saut conditionnel . Par exemple, une instruction « Jump if Equal » (Saut si égal) en langage assembleur x86 effectuera un saut si le drapeau Z (zéro) a été activé par une opération précédente.JE...

Un champ de bits se distingue d'un tableau de bits par le fait que ce dernier sert à stocker un grand ensemble de bits indexés par des entiers et est souvent plus large que n'importe quel type entier pris en charge par le langage. Les champs de bits, quant à eux, tiennent généralement dans un mot machine [ et la désignation des bits est indépendante de leur index numérique

Mise en œuvre

Les champs de bits permettent de réduire la consommation de mémoire lorsqu'un programme nécessite plusieurs variables entières qui auront toujours des valeurs faibles. Par exemple, dans de nombreux systèmes, le stockage d'une valeur entière requiert deux octets (16 bits) de mémoire ; or, certaines valeurs à stocker ne nécessitent qu'un ou deux bits. Le fait de regrouper plusieurs de ces petites variables dans un champ de bits permet un stockage efficace des données en mémoire.

En C, les champs de bits natifs définis par l'implémentation peuvent être créés à l'aide de int , ` int` (en C99 ), ` int` (en C23 ) ou d'autres types définis par l'implémentation. En C++, ils peuvent être créés à l'aide de n'importe quel type entier ou énuméré ; la plupart des compilateurs C le permettent également. Dans ce cas, le programmeur peut déclarer une structure pour un champ de bits qui étiquette et détermine la largeur de plusieurs sous-champs. Les champs de bits adjacents du même type peuvent alors être regroupés par le compilateur dans un nombre réduit de mots, comparé à la mémoire utilisée si chaque « champ » était déclaré séparément.unsigned intsigned int_Bool_BitInt(N)unsigned _BitInt(N)

Pour les langages dépourvus de champs de bits natifs, ou lorsque le programmeur souhaite contrôler la représentation binaire résultante, il est possible de manipuler manuellement les bits au sein d'un type de mot plus large. Dans ce cas, le programmeur peut définir, tester et modifier les bits du champ en utilisant des combinaisons de masquage et d'opérations bit à bit .

Exemples

C

Les champs de bits peuvent être utilisés à l'intérieur des structures en C et C++ .

#include <stdint.h>// opaque et afficher l'énumération Visibilité : uint8_t { NO = 0 , YES = 1 };// style de ligne enum LineStyle : uint8_t { SOLID = 1 , DOTTED = 2 , DASHED = 3 };// Énumération des couleurs Color : uint8_t { NOIR = 0 , ROUGE = 0b001 , VERT = 0b010 , BLEU = 0b100 , JAUNE = ROUGE | VERT , // 011 MAGENTA = ROUGE | BLEU , // 101 CYAN = VERT | BLEU , // 110 BLANC = ROUGE | VERT | BLEU // 111 };const char * couleurs [ 8 ] = { "Noir" , "Rouge" , "Vert" , "Jaune" , "Bleu" , "Magenta" , "Cyan" , "Blanc" };// Propriétés de la boîte de champ de bits struct BoxProps { uint32_t opaque : 1 ; uint32_t fill_color : 3 ; [[ maybe_unused ]] uint32_t filler_a : 4 ; // Remplissage sur 8 bitsuint32_t afficher_bordure : 1 ; uint32_t couleur_bordure : 3 ; uint32_t style_bordure : 2 ;[[ maybe_unused ]] uint8_t filler_b : 0 ; // remplir à l'octet le plus proche (16 bits)uint8_t largeur : 4 ; // Diviser un octet en 2 champs de 4 bits uint8_t hauteur : 4 ; };int main ( ) { BoxProps my_box = { .opaque = YES , .fill_color = RED , .show_border = YES , .border_color = BLUE , .border_style = SOLID , .width = 5 , .height = 10 } ; }

La disposition des champs de bits en C structest définie par l'implémentation . Pour un comportement prévisible d'un compilateur à l'autre, il peut être préférable d'émuler les champs de bits avec un type primitif et des opérateurs binaires :

#include <stdint.h>/** * Chacune de ces directives de préprocesseur définit un seul bit, * correspondant à un bouton de la manette. * L'ordre des boutons correspond à celui de la Nintendo Entertainment System. */ enum Key : uint8_t { KEY_RIGHT = 0b00000001 , KEY_LEFT = 0b00000010 , KEY_DOWN = 0b00000100 , KEY_UP = 0b00001000 , KEY_START = 0b00010000 , KEY_SELECT = 0b00100000 , KEY_B = 0b01000000 , KEY_A = 0b10000000 };// état global uint8_t gameControllerStatus = 0 ;// Définit le statut du contrôleur de jeu à l'aide de OU void onKeyPressed ( uint8_t key ) { gameControllerStatus |= key ; }// Efface le statut du contrôleur de jeu en utilisant ET et ~ (NON binaire) void onKeyReleased ( uint8_t key ) { gameControllerStatus &= ~ key ; }// Vérifie si un bit est activé en utilisant AND uint8_t isPressed ( uint8_t key ) { return gameControllerStatus & key ; }

Rouiller

Bien que Rust ne dispose pas de champs de bits natifs de type C, cela est réalisé à l'aide de masques.

impl BoxProps { // Octet 0 const OPAQUE : u8 = 0b0000_0001 ; const FILL_COLOR_MASK : u8 = 0b0000_1110 ;// Octet 1 const SHOW_BORDER : u8 = 0b0000_0001 ; const BORDER_COLOR_MASK : u8 = 0b0000_1110 ; const BORDER_STYLE_MASK : u8 = 0b0011_0000 ;// Octet 2 const WIDTH_MASK : u8 = 0b0000_1111 ; const HEIGHT_MASK : u8 = 0b1111_0000 ; }impl BoxProps { fn opaque ( & self ) -> bool { self . raw [ 0 ] & Self :: OPAQUE != 0 }fn set_opaque ( & mut self , v : bool ) { self.raw [ 0 ] = ( self.raw [ 0 ] & ! Self :: OPAQUE ) | ( v as u8 ) ; }fn fill_color ( & self ) - > u8 { ( self.raw [ 0 ] & Self :: FILL_COLOR_MASK ) >> 1 }fn set_fill_color ( & mut self , v : u8 ) { self.raw [ 0 ] = ( self.raw [ 0 ] & ! Self :: FILL_COLOR_MASK ) | ( ( v & 0b111 ) << 1 ) ; }fn largeur ( & self ) - > u8 { self.raw [ 2 ] & Self :: WIDTH_MASK }fn hauteur ( & self ) - > u8 { ( self.raw [ 2 ] & Self :: HEIGHT_MASK ) >> 4 } }

Registre d'état du processeur

Le registre d'état d'un processeur est un champ de bits composé de plusieurs bits d'indicateur. Chaque bit d'indicateur décrit des informations sur l'état actuel du processeur. À titre d'exemple, le registre d'état du processeur 6502 est présenté ci-dessous :

Ces bits sont positionnés par le processeur à la suite du résultat d'une opération. Certains bits (comme les indicateurs de retenue, de désactivation d'interruption et de décimal) peuvent être contrôlés explicitement à l'aide des instructions de mise à 1 et de mise à 0. De plus, des instructions de branchement permettent de modifier l'exécution en fonction de l'état actuel d'un indicateur.

Par exemple, après une ADCinstruction (Add with Carry), l' BVSinstruction (Branch on oVerflow Set) peut être utilisée pour effectuer un saut en fonction du fait que l' indicateur de dépassement a été défini par le processeur à la suite du résultat de l'instruction d'addition.

Extraction de bits à partir de mots-clés.

Dans un champ de drapeaux, on peut extraire un sous-ensemble de valeurs en effectuant un ET logique avec un masque . De nombreux langages prennent en charge l' opérateur de décalage ( < < ) qui 1 << naligne un bit à la position n. La plupart prennent également en charge l' opérateur ET logique (&) pour isoler la valeur d'un ou plusieurs bits.

Si l'octet d'état d'un périphérique est 0x67 et que le 5e bit d'indicateur signale la disponibilité des données, alors l'octet de masque est 0x20 2^5 = 0x20. Un ET logique entre l'octet d'état 0x67 ( en binaire) et l'octet de masque 0x20 ( en binaire) donne 0x20. Cela signifie que le bit d'indicateur est activé, c'est-à-dire que le périphérique a des données disponibles. Si le bit d'indicateur n'avait pas été activé, le résultat aurait été 0, indiquant qu'aucune donnée n'est disponible.0110011100100000

Pour vérifier le n -ième bit d'une variable v , effectuez l'une des opérations suivantes : (les deux sont équivalentes)

bool nth_is_set = ( v & ( 1 << n )) != 0 ; bool nth_is_set = ( v >> n ) & 1 ;

Modification de certains éléments dans les mots de drapeau

L'écriture, la lecture ou la modification des bits dans les drapeaux ne peuvent être effectuées qu'à l'aide des opérations OU, ET et NON, opérations rapides pour le processeur. Pour activer un bit, effectuez un OU logique entre l'octet d'état et un octet de masque. Tout bit activé dans l'octet de masque ou l'octet d'état sera activé dans le résultat.

Pour inverser l'état d'un bit, effectuez un XOR entre l'octet d'état et l'octet de masque. Cela activera le bit s'il est à zéro, ou le désactivera s'il est à un.

Plus d articles de Worldlex Wiki

Revenez a l index pour explorer davantage de pages sur l histoire, la science, la culture, la geographie et la societe en francais.

Explorer l index