Qu'est-ce que la syntaxe de structure C ++ & # 8220; a: b & # 8221; signifier
-
05-07-2019 - |
Question
Si j'ai une structure C ++, définissant un mot de données 64 bits tel que ..
struct SMyDataWord
{
int Name : 40;
int Colour : 24;
};
Qu'est-ce que la syntaxe : 40
signifie ... Cela signifie-t-il que les 40 premiers bits sont réservés au nom et les 24 bits restants à la couleur?
C’est ainsi qu’il semble être utilisé, mais je ne l’ai jamais vu auparavant.
La solution
Les champs de bits, transférés du C. Nom
a une largeur de 40 bits, Couleur
a une largeur de 24 bits. Votre structure a donc au moins 64 bits. Sur mon système, 64 bits correspondraient à 8 octets.
Autres conseils
Oui, c'est la syntaxe de champs de bits . Ils sont couramment utilisés pour définir des structures mappées sur des registres matériels. Si vous décidez de les utiliser, vous devez garder à l’esprit certaines choses. En premier lieu, vous ne pouvez pas savoir comment le compilateur fait la mise en page, le classement et le remplissage dans les octets constituant les champs. avec le même compilateur mais avec des paramètres d’optimisation différents).
C'est une définition de bitfield.
Nom est un entier capable de stocker exactement 40 bits d'informations. La couleur peut stocker 24 bits.
Ceci est souvent fait pour économiser de l'espace dans les structures souvent nécessaires, ou pour compresser le code jusqu'à une taille facile à gérer pour le CPU (dans votre cas, 64 bits. S'adapte exactement dans un registre de CPU sur une machine 64 bits).
Le code qui accède aux champs de bits s'exécutera cependant un peu plus lentement.
N'oubliez pas que presque tout sur champs de bits est la mise en œuvre dépendant. Par exemple, si les bits sont stockés de gauche à droite ou de droite à gauche dépend de la réelle architecture matérielle. En outre, chaque compilateur utilise un membre différent modèle d'alignement, c'est pourquoi la taille de BillingRec optimisé est de 12 octets plutôt que 9. Vous ne pouvez pas prendre un adresse de champ de bits, ni pouvez-vous créer un tableau de bits. Enfin, sur la plupart implémentations l'utilisation de champs de bits encourt de la vitesse au-dessus. Par conséquent, quand vous optimisez votre code, mesurez le effet d'une certaine optimisation et ses compromis avant de décider d'utiliser il.
Ici sizeof
montre bien ce qui se passe sous le capot:
#include <iostream>
#include <climits>
struct bc_1 {
int a : 1;
int b : 1;
};
struct bc_2 {
int a : 31;
int b : 1;
};
struct bc_3 {
int a : 32;
int b : 1;
};
struct bc_4 {
int a : 31;
int b : 2;
};
struct bc_5 {
int a : 32;
int b : 32;
};
struct bc_6 {
int a : 40;
int b : 32;
};
struct bc_7 {
int a : 63;
int b : 1;
};
int main(int argc, char * argv[]) {
std::cout << "CHAR_BIT = " << CHAR_BIT;
std::cout << " => sizeof(int) = " << sizeof(int) << std::endl;
std::cout << "1, 1: " << sizeof(struct bc_1) << std::endl;
std::cout << "31, 1: " << sizeof(struct bc_2) << std::endl;
std::cout << "32, 1: " << sizeof(struct bc_3) << std::endl;
std::cout << "31, 2: " << sizeof(struct bc_4) << std::endl;
std::cout << "32, 32: " << sizeof(struct bc_5) << std::endl;
std::cout << "40, 32: " << sizeof(struct bc_6) << std::endl;
std::cout << "63, 1: " << sizeof(struct bc_7) << std::endl;
}
Ce qui suit dépend de votre compilateur et de votre système d'exploitation, et éventuellement de votre matériel. Sur macOS avec gcc-7 (avec un CHAR_BIT
= 8, un int
32 bits (c'est-à-dire la moitié de la longueur de long de 64 bits
) a sizeof (int)
= 4) c'est la sortie que je vois:
CHAR_BIT = 8 => sizeof(int) = 4
1, 1: 4
31, 1: 4
32, 1: 8
31, 2: 8
32, 32: 8
40, 32: 12
63, 1: 8
Cela nous dit plusieurs choses: si les deux champs de type int
entrent dans un seul int
(c'est-à-dire 32 bits dans l'exemple ci-dessus), le compilateur n'alloue qu'un seul La mémoire de int
( bc_1
et bc_2
). Une fois, un seul int
ne peut plus contenir les champs de bits, nous en ajoutons un second ( bc_3
et bc_4
). Notez que bc_5
est saturé.
Il est intéressant de noter que nous pouvons " sélectionner " plus de bits que permis. Voir bc_6
. Ici g ++ - 7 donne un avertissement:
bitfields.cpp::30:13: warning: width of 'bc_6::a' exceeds its type
int a : 40;
^~
Notez que: clang ++ explique cela plus en détail
bitfields.cpp:30:9: warning: width of bit-field 'a' (40 bits) exceeds the width of its type; value will be truncated to 32 bits [-Wbitfield-width]
int a : 40;
^
Cependant, il semble que sous le capot, le compilateur alloue une autre mémoire à int
. Ou à tout le moins, il détermine la taille correcte. Je suppose que le compilateur nous avertit de ne pas accéder à cette mémoire car int a = bc_6 :: a
(je parierais que int a
n'aurait alors que les 32 premiers bits de champ bc_6 :: a
...). Ceci est confirmé par bc_7
dont la taille totale est celle de deux int
, mais le premier champ en couvre la plupart.
Finalement, remplacer int
par long
dans l'exemple ci-dessus se comporte comme prévu:
CHAR_BIT = 8 => sizeof(long) = 8
1, 1: 8
31, 1: 8
32, 1: 8
31, 2: 8
32, 32: 8
40, 32: 16
63, 1: 8