Champs de bits en c++ [Résolu]

Signaler
Messages postés
581
Date d'inscription
jeudi 28 novembre 2002
Statut
Membre
Dernière intervention
13 juin 2021
-
Messages postés
581
Date d'inscription
jeudi 28 novembre 2002
Statut
Membre
Dernière intervention
13 juin 2021
-
Bonjour,
je suis un peu perdu avec la taille des champs de bits en c++.
Exemples:
  struct ACLOSE_TRACK {          // taille 10 au lieu de 13
        UCHAR OperationCode;    // 0x5B - SCSIOP_CLOSE_TRACK_SESSION
        UCHAR Immediate : 1;
        UCHAR Reserved1 : 7;
        UCHAR Track     : 1;
        UCHAR Session   : 1;
        UCHAR Reserved2 : 6;
        UCHAR Reserved3;
        UCHAR TrackNumber[2];
        UCHAR Reserved4[3];
        UCHAR Control;
    };

struct Date {           //taile 4
   unsigned short nWeekDay  : 3;    // 0..7   (3 bits)
   unsigned short nMonthDay : 6;    // 0..31  (6 bits)
   unsigned short nMonth    : 5;    // 0..12  (5 bits)
   unsigned short nYear     : 8;    // 0..100 (8 bits)
}


Quel est la regle applique permettant de trouver 10 au lieu de 13 ??????

8 réponses

Messages postés
568
Date d'inscription
dimanche 7 février 2016
Statut
Membre
Dernière intervention
13 juin 2021
6
L'alignement n'a rien de particulier avec le champs de bits. Le lien est que les champs de bits sont regroupés dans un type de variables (char, short, ...)
L'alignement est une contrainte liée directement au microprocesseur. Suivant son type, le microprocesseur peut interdire de positionner une variable à certaines valeurs d'adresses. Sur la plupart des processeurs:
bool, std::byte, char8_t et char : adresse quelconque
short, char16_t : adresse doit être paire
wchar_t, int, long, long long : adresse doit être un multiple de leur taille
float, char32_t : adresse doit être multiple de 4
double : adresse doit être multiple de 8
Cette contrainte sur les types simples donne une contrainte sur les struct/class:
La taille d'une struct/class doit être un multiple de son composant ayant le plus grand alignement.
struct ShortDoubleEtChar {
   short a;    // taille 2, alignement 2 -> positions 0à1
   double b;   // taille 8, alignement 8 -> position 8à15 (car 2,3,...,7 impossibles)
   char c;     // taille 1, alignement 1 -> position 16
}; // alignement 8, taille 24 octets 'le plus petit multiple de 8 après 17 est 24'

Pour s'assurer qu'une struct/class ne consomme pas inutilement de la mémoire, il faut commencer par les éléments ayant le + grand alignement jusqu'à ceux ayant le plus petit. La struct précédente arriverait alors à la taille irréductible de 16.
Messages postés
3840
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
11 juin 2021
121
Bonjour.

Ce n'est pas un souci de C++, mais de bitfield.
Si tu retires les " : n" tu verras qu'un sizeof te donne bien 13.

En effet, ça serait équivalent à:
struct ACLOSE_TRACK { // 104 / 8 => 13
  UCHAR OperationCode : 8;
  UCHAR Immediate : 8;
  UCHAR Reserved1 : 8;
  UCHAR Track : 8;
  UCHAR Session : 8;
  UCHAR Reserved2 : 8;
  UCHAR Reserved3 : 8;
  UCHAR TrackNumber[2]; // 2* 8
  UCHAR Reserved4[3]; // 3 * 8
  UCHAR Control : 8;
};
// Ta version: 8+1+7+1+1+6+8+2*8+3*8+8 = 80
// 80 / 8 => 10


Donc si tu as de quoi "packed" les bits, en mettant 1 + 7 au lieu de 8 + 8, et bien tu économises 1 octet (8 bits).
Si tu regardes bien ta structure, tu as bien 10 octets au lieu de 13, parce que tu "économises" 3 octets (24 bits).


Améliorer votre expérience CodeS-SourceS avec ce plugin:
https://codes-sources.commentcamarche.net/forum/affich-10000111-plugin-better-cs-2#cptpingu-signature
Messages postés
568
Date d'inscription
dimanche 7 février 2016
Statut
Membre
Dernière intervention
13 juin 2021
6
Bonjour,

Je vais commenter le cas de
Date
.
A chaque nouveau champ de bits, le compilateur va essayer de le mettre dans le même mot que le précédent. s'il n'y a plus la place, il doit utiliser un nouveau mot.
   unsigned short nWeekDay  : 3;
// 1er unsigned short : utilise 3 bits, restent 15
   unsigned short nMonthDay : 6;
// le même unsigned short : utilise 3+6 bits, restent 7
   unsigned short nMonth    : 5;
// le même unsigned short : utilise 3+6+5 bits, restent 2
   unsigned short nYear     : 8;
// plus la place pour mettre 8 bits
// 2ième unsigned short : utilise 8 bits, restent 8
On donc besoin de 2
unsigned short
soit 4 octets.
Si on avait utilisé
unsigned char
à la place, en essayant on voit que ça fait aussi 4 octets. Sauf si on change l'ordre, on peut alors avoir une solution à 3 octets.
Messages postés
581
Date d'inscription
jeudi 28 novembre 2002
Statut
Membre
Dernière intervention
13 juin 2021
2
Merci pour les réponses.
Ce qui est important pour moi ,c'est de connaitre la manière de procéder du compilateur.
S'il prend la totalité du nombre de bits et détermine le nombre de variables de X size pouvant contenir ce nombre de bits,le résultat peut être différent que si il utilise
un cumul des derniers bits pouvant être contenus dans une variable de X size en rajoutant une variable s'il y a débordement.
dans le genre piège ,faisant une taille de 4
typedef  struct _st
  {
    int champ_1: 6,
     champ_2: 6,
     champ_3: 1,
     champ_4: 1,
     champ_5: 2;
  }st;

Pour bien imager mon propos taille 2
struct Date {           //taile 2
   unsigned short nWeekDay  : 1;    
   unsigned short nMonthDay : 1;   
   unsigned short nMonth    : 1;    
   unsigned short nYear     : 1;    
   unsigned short lunaire    : 1;    
   unsigned short martien    : 1;    
   unsigned short saturnien    : 1;    
}

Messages postés
568
Date d'inscription
dimanche 7 février 2016
Statut
Membre
Dernière intervention
13 juin 2021
6
Comme je l'ai écris, le remplissage se fait ligne par ligne.
Un cas plus tordu. Saurais-tu trouver la taille de cette date (il faut connaître un concept de plus appelé alignement)?
struct Date {                   // taille ?
   unsigned short nWeekDay : 3; // 0à1: (3 bits)
   unsigned char nMonthDay : 6; // 2: (6 bits)
                                // alignement:3
   unsigned int nMonth : 5;     // 4à7: (5 bits)
   unsigned char nYear     : 8; // 8: (8 bits)
                                // alignement:9à11
};
Messages postés
581
Date d'inscription
jeudi 28 novembre 2002
Statut
Membre
Dernière intervention
13 juin 2021
2
12 , surprenant effectivement.
Je ne vois pas comment est provoque l'alignement ? (defaut QWORD ?).
Pour le cours,http://luce.yves.pagesperso-orange.fr/align.htm
dans

struct Date { //taile 2
unsigned short nWeekDay : 1;
unsigned short nMonthDay : 1;
unsigned short nMonth : 1;
unsigned short nYear : 1;
unsigned short lunaire : 1;
unsigned short martien : 1;
unsigned short saturnien : 1;
}


Qu'est ce qui provoque la création du deuxième BYTE ? L'alignement ?

ici https://docs.microsoft.com/fr-fr/cpp/cpp/cpp-bit-fields?view=msvc-160
en observant le schéma , dois je conclure qu'un champ de bits a une taille minimum de 32 bits ?.
Messages postés
581
Date d'inscription
jeudi 28 novembre 2002
Statut
Membre
Dernière intervention
13 juin 2021
2
Les choses s'éclaircissent un petit peu:
Ici l'énoncé des règles:

champs de bits = bits de X a Y
contenant de champs = variable de 4,8,16,32,64 bits
Taille par défaut du contenant des champs,int ,4 bytes
Alignement par défaut int,8 bytes sinon sur taille contenant des champs
Taille minimum structure champs de bits ,2 bytes avec un champ de bit short ,2 bytes
Taille du contenant des champs de bits acceptés:
------ bool, char, char8_t, unsigned char, signed char, __int8 1 byte
------ char16_t, __int16, short, unsigned short, wchar_t, __wchar_t 2 bytes
------ char32_t, float, __int32, int, unsigned int, long, unsigned long 4 bytes
------ double, __int64, long double, long long, unsigned long long 8 bytes
Déclaration:
Les bits vont du poids faible au poids fort. premier:3,deux:4 donne premier:bit 0 a 2,deux bits 3 a 6
Créations de nouveau contenant de champs:
Lorsque la Somme des bits précédents excède la taille défini du contenant.
Alignement:
          • Peut etre provoque par un champ de bits NULL :0
          • L'alignement s'effectue sur la taille du contenant ou le minimum accepté ,word
          • L'alignement byte n'étant pas accepté ,on prend l'alignement par défaut int,4 bytes
          • C'est ce qui fait que la taille minimum d'une structure est obtenu avec un contenant de champ short,2 bytes
          • Un changement de valeur de contenant dans la structure provoque un réalignement dont la taille est celle du nouveau contenant


Voila ,si vous voyez une erreur merci de me la signaler.
Messages postés
581
Date d'inscription
jeudi 28 novembre 2002
Statut
Membre
Dernière intervention
13 juin 2021
2
J'ai réussi a créer une structure d'une taille de 1 byte (bool)
+ les explications ,cela m'oblige a corriger légèrement l'énoncé ,plus clair

champs de bits = bits de X a Y
contenant de champs = variable de 8,16,32,64 bits
Taille par défaut du contenant des champs,int ,4 bytes
Alignement par defaut int,8 bytes sinon sur taille contenant des champs
Taille minimum structure champs de bits ,1 byte avec un champ de bit bool ,1 byte
Taille du contenant des champs de bits acceptés:
------ bool, char, char8_t, unsigned char, signed char, __int8 1 byte
------ char16_t, __int16, short, unsigned short, wchar_t, __wchar_t 2 bytes
------ char32_t, float, __int32, int, unsigned int, long, unsigned long 4 bytes
------ double, __int64, long double, long long, unsigned long long 8 bytes
Déclaration:
Les bits vont du poids faible au poids fort. premier:3,deux:4 donne premier:bit 0 a 2,deux bits 3 a 6.
Création de nouveau contenant de champs:
Lorsque la Somme des bits précédents excède la taille définie du contenant.
Alignement et taille de structure:
----- défini par défaut par la plus grande variable
----- Peut être provoque par un champ de bits NULL <unsigned : 0> size DWORD 32 bits,4 bytes
----- La taille de la structure est un multiple de l'alignement