J'ai lu que l'ordre des champs de bits dans une structure est spécifique à la plate-forme. Qu'en est-il si j'utilise différentes options d'emballage spécifiques au compilateur, ces données de garantie seront-elles stockées dans le bon ordre au fur et à mesure qu'elles sont écrites? 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 étaient disposés en mémoire tels qu'ils sont affichés. Message.version
était les 3 premiers bits du tampon, et Message.type
suivit. Si je trouve des options de compression de structure équivalentes pour divers compilateurs, est-ce que ce sera multiplateforme?
c++
c
bit-manipulation
endianness
bit
Dewald
la source
la source
Réponses:
Non, il ne sera pas entièrement portable. Les options d'emballage pour les structures sont des extensions et ne sont elles-mêmes pas entièrement portables. En plus de cela, C99 §6.7.2.1, paragraphe 10 dit: "L'ordre d'attribution des champs de bits dans une unité (d'ordre haut à bas ou d'ordre bas à haut) est défini par l'implémentation."
Même un seul compilateur peut disposer le champ de bits différemment selon l'endianness de la plate-forme cible, par exemple.
la source
packed
n'appliquer la commande: stackoverflow.com/questions/1756811/... comment faire respecter l' ordre des bits: stackoverflow.com/questions/6728218/gcc-compiler-bit-orderLes champs de bits varient considérablement d'un compilateur à l'autre, désolé.
Avec GCC, les machines big endian placent les bits big end en premier et les machines little endian disposent les bits little end first.
K&R dit: "Les membres de champ [bits] adjacents des structures sont emballés dans des unités de stockage dépendant de l'implémentation dans une direction dépendant de l'implémentation. Lorsqu'un champ suivant un autre champ ne rentre pas ... il peut être divisé entre les unités ou l'unité peut être rembourré. Un champ sans nom de largeur 0 force ce remplissage ... "
Par conséquent, si vous avez besoin d'une disposition binaire indépendante de la machine, vous devez le faire vous-même.
Cette dernière déclaration s'applique également aux champs non binaires en raison du remplissage - cependant, tous les compilateurs semblent avoir un moyen de forcer le compactage d'octets d'une structure, comme je vois que vous l'avez déjà découvert pour GCC.
la source
Les champs de bits doivent être évités - ils ne sont pas très portables entre les compilateurs, même pour la même plate-forme. de la norme C99 6.7.2.1/10 - "Spécificateurs de structure et d'union" (il existe une formulation similaire dans la norme C90):
Vous ne pouvez pas garantir si un champ de bits `` couvrira '' une limite int ou non et vous ne pouvez pas spécifier si un champ de bits commence à l'extrémité inférieure de l'int ou à l'extrémité supérieure de l'int (cela est indépendant du fait que le processeur est big-endian ou little-endian).
Préférez les masques de bits. Utilisez des inlines (ou même des macros) pour définir, effacer et tester les bits.
la source
_BIT_FIELDS_LTOH
et_BIT_FIELDS_HTOL
endianness parle d'ordres d'octets et non d'ordres de bits. De nos jours , il est sûr à 99% que les ordres de bits sont corrigés. Cependant, lors de l'utilisation de champs de bits, l'endianness doit être pris 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 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 source
La plupart du temps, probablement, mais ne pariez pas la ferme dessus, car si vous vous trompez, vous perdrez gros.
Si vous avez vraiment, vraiment besoin d'informations binaires identiques, vous devrez créer des champs de bits avec des masques de bits - par exemple, vous utilisez un court non signé (16 bits) pour Message, puis faites des choses comme versionMask = 0xE000 pour représenter les trois bits les plus hauts.
Il y a un problème similaire avec l'alignement dans les structures. Par exemple, les processeurs Sparc, PowerPC et 680x0 sont tous big-endian, et la valeur par défaut commune pour les compilateurs Sparc et PowerPC est d'aligner les membres de structure sur des limites de 4 octets. Cependant, un compilateur que j'ai utilisé pour 680x0 uniquement aligné sur des limites de 2 octets - et il n'y avait aucune option pour changer l'alignement!
Ainsi, pour certaines structures, les tailles sur Sparc et PowerPC sont identiques, mais plus petites sur 680x0, et certains des membres sont dans des décalages mémoire différents dans la structure.
C'était un problème avec un projet sur lequel j'ai travaillé, car un processus serveur s'exécutant sur Sparc interrogeait un client et découvrait qu'il était big-endian, et supposait qu'il pouvait simplement éjecter des structures binaires sur le réseau et que le client pouvait faire face. Et cela a bien fonctionné sur les clients PowerPC et a planté énormément sur les clients 680x0. Je n'ai pas écrit le code et il a fallu un certain temps pour trouver le problème. Mais c'était facile à réparer une fois que je l'ai fait.
la source
Merci @BenVoigt pour votre commentaire très utile commençant
Source de Linux n'utiliser un champ de bits pour correspondre à une structure externe: /usr/include/linux/ip.h a ce code pour le premier octet d'un datagramme IP
struct iphdr { #if defined(__LITTLE_ENDIAN_BITFIELD) __u8 ihl:4, version:4; #elif defined (__BIG_ENDIAN_BITFIELD) __u8 version:4, ihl:4; #else #error "Please fix <asm/byteorder.h>" #endif
Cependant, à la lumière de votre commentaire, je renonce à essayer de faire fonctionner cela pour le champ de bits multi-octets frag_off .
la source
Bien sûr, la meilleure réponse est d'utiliser une classe qui lit / écrit les champs de bits sous forme de flux. L'utilisation de la structure de champ de bits C n'est tout simplement pas garantie. Sans oublier qu'il est considéré comme non professionnel / paresseux / stupide d'utiliser cela dans le codage du monde réel.
la source