93 votes

C / C ++: Ordre et alignement du champ de bits de force

J'ai lu que l'ordre des champs de bits à l'intérieur d'une structure de la plate-forme. Si j'utilise les différentes compilateur spécifique de l'emballage, cette garantie les données sont stockées dans le bon ordre, comme ils sont écrits? Par exemple:

struct Message
{
  unsigned int version : 3;
  unsigned int type : 1;
  unsigned int id : 5;
  unsigned int data : 6;
} __attribute__ ((__packed__));

Sur un processeur Intel avec le compilateur GCC, les champs ont été mis en mémoire comme ils sont indiqués. Message.version a les 3 premiers bits dans la mémoire tampon, et le Message.type de suivi. Si je trouve l'équivalent struct emballage options pour différents compilateurs, ce que ce sera de la croix-plate-forme?

112voto

Stephen Canon Points 58003

Non, ce ne sera pas entièrement portable. Les options d'emballage pour les structures sont des extensions et ne sont pas entièrement portables. De plus, le paragraphe 10 de C99 §6.7.2.1 indique: "L'ordre d'attribution des champs de bits au sein d'une unité (ordre élevé à ordre faible ou ordre faible à ordre élevé) est défini par la mise en oeuvre."

Même un seul compilateur peut disposer le champ de bits différemment en fonction de l'endianité de la plate-forme cible, par exemple.

48voto

Joshua Points 13231

Champs de bits varient largement d'un compilateur de compilateur, désolé.

Avec GCC, big endian machines à poser les bits de big fin de la première et little endian machines à poser les bits de la petite fin de la première.

K&R dit "Adjacent [bit]champ de membres des structures sont emballés dans la mise en œuvre dépendant des unités de stockage dans une mise en œuvre dépendant de la direction. Lorsqu'un champ suivant un autre champ ne seront pas s'adapter ... il peut être divisé entre les unités ou l'unité peut être rembourré. Un sans nom domaine de la largeur 0 les forces de ce remplissage..."

Par conséquent, si vous avez besoin de la machine binaire et indépendante de mise en page, vous devez le faire vous-même.

Cette dernière affirmation s'applique également aux non-bitfields en raison de rembourrage -- cependant, tous les compilateurs semblent avoir un moyen de forcer l'octet d'emballage d'une structure, comme je vous vois déjà découvert pour GCC.

37voto

Michael Burr Points 181287

Bitfields doit être évitée - ils ne sont pas très portable entre les compilateurs pour la même plate-forme. à partir du standard C99 6.7.2.1/10 - "la Structure et de l'union des prescripteurs" (il y a un libellé similaire dans la norme C90):

Une mise en œuvre peut attribuer tous adressable de l'unité de stockage assez grand pour contenir un champ de bits. Si il reste suffisamment d'espace, un peu de champ qui suit immédiatement un autre bit-champ dans une structure doivent être emballées dans les bits de la même unité. Si l'espace est insuffisant reste, si un peu de champ qui ne correspond pas à y mettre de l'unité ou des chevauchements unités adjacentes est mise en œuvre définies. La commande de l'allocation de bit-domaines au sein d'une unité (haut-bas ou bas-haut) est mise en œuvre définies. L'alignement de la adressable de l'unité de stockage est indéterminé.

Vous ne pouvez pas garantir qu'un peu de champ 'span' int limite ou pas et vous ne pouvez pas indiquer si un champ de bits commence au bas de l'int ou le haut de gamme de l'int (ceci est indépendant de savoir si le processeur est en big-endian ou little-endian).

Préférez les masques de bits. Utilisation inlines (ou même des macros) pour définir, clair et tester les bits.

11voto

pierr Points 9148

endianness parlent d’ordres sur les octets et non d’ordres. De nos jours , 99% sont certains que les ordres de bits sont fixes. Cependant, lors de l'utilisation de champs de bits, l'endianité doit être prise en compte. Voir l'exemple ci-dessous.

 #include <stdio.h>

typedef struct tagT{

    int a:4;
    int b:4;
    int c:8;
    int d:16;
}T;


int main()
{
    char data[]={0x12,0x34,0x56,0x78};
    T *t = (T*)data;
    printf("a =0x%x\n" ,t->a);
    printf("b =0x%x\n" ,t->b);
    printf("c =0x%x\n" ,t->c);
    printf("d =0x%x\n" ,t->d);

    return 0;
}

//- big endian :  mips24k-linux-gcc (GCC) 4.2.3 - big endian
a =0x1
b =0x2
c =0x34
d =0x5678
// - little endian : gcc (Ubuntu 4.3.2-1ubuntu11) 4.3.2
a =0x2
b =0x1
c =0x34
d =0x7856
 

7voto

Bob Murphy Points 3386

La plupart du temps, sans doute, mais ne pas parier la ferme sur elle, parce que si vous vous trompez, vous perdez beaucoup.

Si vous avez vraiment, vraiment besoin d'avoir à l'identique des informations binaires, vous aurez besoin de créer bitfields avec des masques de bits - par exemple, vous utiliser un unsigned short (16 bits) pour le Message, puis faire des choses comme versionMask = 0xE000 pour représenter les trois plus grands bits.

Il y a un problème similaire avec alignement à l'intérieur des structures. Par exemple, Sparc, PowerPC, et 680x0 Processeurs sont tous les big-endian, et de la politique par défaut pour Sparc, PowerPC compilateurs est d'aligner les membres de la structure sur 4 octets limites. Cependant, un compilateur, j'ai utilisé pour 680x0 seulement alignés sur 2 octets limites - et il n'y a pas d'option pour modifier l'alignement!

Donc, pour certaines structures, les tailles sur Sparc et PowerPC sont identiques, mais de plus petite taille sur 680x0, et certains membres sont dans différents décalages de mémoire au sein de la structure.

C'était un problème avec un projet, j'ai travaillé sur, car un serveur de processus en cours d'exécution sur Sparc serait requête d'un client et de trouver qu'il était big-endian, et suppose qu'il pourrait tout simplement couler binaire des structures sur le réseau et que le client pourrait faire face. Et qui a bien fonctionné sur PowerPC clients, et s'est écrasé grand-temps sur 680x0 clients. Je n'ai pas écrit le code, et il a fallu un certain temps pour trouver le problème. Mais il était facile de fixer une fois que j'ai fait.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X