Recherche…


Introduction

Les champs de bits compressent étroitement les structures C et C ++ pour réduire la taille. Cela semble indolore: spécifiez le nombre de bits pour les membres, et le compilateur fait le travail de co-mingling bits. La restriction est l’incapacité de prendre l’adresse d’un membre du champ de bits, car elle est stockée de manière concomitante. sizeof() est également interdit.

Le coût des champs de bits est un accès plus lent, car la mémoire doit être récupérée et les opérations au niveau des bits appliquées pour extraire ou modifier les valeurs des membres. Ces opérations ajoutent également à la taille de l'exécutable.

Remarques

Quel est le coût des opérations binaires? Supposons une structure de champ non binaire simple:

struct foo {
    unsigned x;
    unsigned y;
}
static struct foo my_var;

Dans un code ultérieur:

my_var.y = 5;

Si sizeof (unsigned) == 4 , alors x est stocké au début de la structure et y est stocké 4 octets. Le code assembleur généré peut ressembler à:

loada register1,#myvar     ; get the address of the structure
storei register1[4],#0x05  ; put the value '5' at offset 4, e.g., set y=5

C'est simple parce que x n'est pas mêlé à y. Mais imaginez redéfinir la structure avec des champs de bits:

struct foo {
    unsigned x : 4; /* Range 0-0x0f, or 0 through 15 */
    unsigned y : 4;
}

4 bits seront attribués à x et y , partageant un seul octet. La structure ainsi occupe 1 octet, au lieu de 8. Considérons l'ensemble pour définir y maintenant, en supposant qu'il se retrouve dans le quartet supérieur:

loada  register1,#myvar        ; get the address of the structure
loadb  register2,register1[0]  ; get the byte from memory
andb   register2,#0x0f         ; zero out y in the byte, leaving x alone
orb    register2,#0x50         ; put the 5 into the 'y' portion of the byte
stb    register1[0],register2  ; put the modified byte back into memory

Cela peut être un bon compromis si nous avons des milliers ou des millions de ces structures, et cela aide à garder la mémoire dans le cache ou à empêcher le swap - ou pourrait gonfler l’exécutable pour aggraver ces problèmes et ralentir le traitement. Comme pour toutes choses, faites preuve de discernement.

Utilisation du pilote de périphérique: évitez les champs de bits comme stratégie d'implémentation intelligente pour les pilotes de périphérique. Les dispositions de stockage sur champ de bits ne sont pas nécessairement cohérentes entre les compilateurs, ce qui rend ces implémentations non portables. La lecture-modification-écriture pour définir les valeurs peut ne pas faire ce que les périphériques attendent, provoquant des comportements inattendus.

Déclaration et utilisation

struct FileAttributes
{
    unsigned int ReadOnly: 1;    
    unsigned int Hidden: 1;
};

Ici, chacun de ces deux champs occupera 1 bit en mémoire. Il est spécifié par : 1 expression après les noms de variable. Le type de base du champ de bits peut être tout type entier (int 8 bits à 64 bits int). L'utilisation d'un type unsigned est recommandée, sinon des surprises peuvent survenir.

Si plus de bits sont requis, remplacez "1" par le nombre de bits requis. Par exemple:

struct Date
{
    unsigned int Year : 13; // 2^13 = 8192, enough for "year" representation for long time
    unsigned int Month: 4;  // 2^4 = 16, enough to represent 1-12 month values.
    unsigned int Day:   5;  // 32
};

La structure entière n'utilise que 22 bits, et avec les paramètres de compilateur normaux, la sizeof cette structure serait de 4 octets.

L'utilisation est assez simple. Déclarez simplement la variable et utilisez-la comme une structure ordinaire.

Date d;

d.Year = 2016;
d.Month = 7;
d.Day =  22;

std::cout << "Year:" << d.Year << std::endl <<
        "Month:" << d.Month << std::endl <<
        "Day:" << d.Day << std::endl;


Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow