Question

Je lis que l'ordre des champs de bits dans un struct est plate-forme spécifique. Qu'en est-il si j'utilise différentes options d'emballage spécifiques au compilateur, ces données ne sont stockées de garantie 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é aménagés dans la mémoire comme ils sont présentés. Message.version sont les 3 premiers bits dans la mémoire tampon, et Message.type suivi. Si je trouve des options équivalentes d'emballage struct pour divers compilateurs, cela sera multi-plateforme?

Était-ce utile?

La solution

Non, il ne sera pas entièrement portable. options pour struct d'emballage sont des extensions, et sont eux-mêmes pas entièrement portable. En plus de cela, C99 §6.7.2.1, paragraphe 10 dit: « L'ordre d'attribution des champs de bits au sein d'une unité (haute pour ordre faible ou à faible ordre à ordre élevé) est défini par l'implémentation. »

Même un seul compilateur peut mettre le champ peu différemment selon le boutisme de la plate-forme cible, par exemple.

Autres conseils

Les champs de bits varient considérablement d'un compilateur compilateur, désolé.

Avec GCC, les grandes machines endian Étalez les bits grande première extrémité et petites machines endian Étalez les bits peu en premier.

K & R dit « Adjacent [BIT-] membres sur le terrain des structures sont emballées dans des unités de stockage en fonction de la mise en œuvre dans une direction dépendant de l'implémentation. Lorsqu'un champ suivant un autre domaine ne rentre pas ... il peut être divisé entre les unités ou unité peut être remplie. Un champ anonyme de largeur 0 forces ce rembourrage ... "

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

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

.

Bitfields doit être évité - ils ne sont pas très mobiles entre les compilateurs même pour la même plate-forme. de la norme C99 6.7.2.1/10 - "Structure et union" spécificateurs (il y a un libellé similaire dans la norme C90):

  

Une mise en œuvre peut allouer une unité de stockage adressable assez grand pour contenir un champ de bits. Si l'espace reste, un peu de champ qui suit immédiatement un autre champ de bits dans une structure doit être emballé dans des bits adjacents de la même unité. Si l'espace est insuffisant reste, que ce soit un peu sur le terrain qui ne correspond pas est mis dans l'unité suivante ou chevauche les unités adjacentes est définie par l'implémentation. L'ordre d'affectation des champs de bits dans une unité (d'ordre élevé à faible ordre ou d'ordre inférieur à ordre élevé) est définie par l'implémentation. L'alignement de l'unité de stockage adressable est non spécifiée.

Vous ne pouvez pas garantir si un champ de bit « durée » une limite int ou non, et vous ne pouvez pas spécifier si un champ de bits commence au bas de gamme de l'int ou le haut de gamme de l'int (ce qui est indépendante de savoir si le processeur est grand-endian ou little-endian).

Préférez bitmasks. Utilisez inline (ou même des macros) pour définir, clair et tester les bits.

boutisme parlent de commandes d'octets non commandes de bits. Aujourd'hui , il est sûr à 99% que les commandes de bits sont fixes. Cependant, lors de l'utilisation bitfields, boutisme doit être pris en comte. 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
 1   2   3   4   5   6   7   8
\_/ \_/ \_____/ \_____________/
 a   b     c           d

// - little endian : gcc (Ubuntu 4.3.2-1ubuntu11) 4.3.2
a =0x2
b =0x1
c =0x34
d =0x7856
 7   8   5   6   3   4   1   2
\_____________/ \_____/ \_/ \_/
       d           c     b   a

La plupart du temps, sans doute, mais ne pariez pas la ferme, parce que si vous avez tort, vous perdrez grand.

Si vous avez vraiment, vraiment besoin d'avoir des informations binaires identiques, vous devrez créer bitfields avec bitmasks - par exemple vous utilisez un court (16 bits) non signé pour un message, puis faire des choses comme versionMask = 0xe000 pour représenter les trois bits les plus hautes.

Il y a un problème similaire avec l'alignement au sein struct. Par exemple, Sparc, PowerPC et 680x0 processeurs sont big-endian, et la valeur par défaut commun pour les compilateurs SPARC et PowerPC est d'aligner les membres de la struct sur les limites de 4 octets. Cependant, un compilateur I utilisé pour 680x0 seulement alignés sur les limites de 2 octets - et il n'y avait pas possibilité de modifier l'alignement

Donc, pour certains struct, les tailles sur Sparc et PowerPC sont identiques, mais plus petit sur 680x0, et certains des membres sont différents décalages de mémoire dans le struct.

Ce fut un problème avec un projet j'ai travaillé, parce qu'un processus serveur en cours d'exécution sur Sparc interrogerait un client et savoir qu'il était grand-boutiste, et supposer qu'il pourrait injecter la struct binaires sur le réseau et le client peut chape. Et cela a bien fonctionné sur les clients PowerPC et écrasements grand temps sur les clients 680x0. 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 je l'ai fait.

Bien sûr, la meilleure réponse est d'utiliser une classe qui lit / écrit des champs de bits comme un flux. En utilisant la structure de champ de bits C est tout simplement pas garanti. Sans oublier qu'il est considéré comme non professionnel / paresseux / stupide d'utiliser ce dans le monde réel de codage.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top