2016-09-22 1 views
0

En travaillant sur certaines structures de cadres, je suis tombé sur un comportement étrange. Je l'ai testé rapidement et le code d'échantillon indépendant avec ce qui suit:Bizarre struct packing

struct non_alligned_struct 
{ 
    uint8_t flag; 

    // start of uint32 bit fields 
    uint32_t a:2; 
    uint32_t b:2; 
    uint32_t c:1; 
    uint32_t d:1; 
    uint32_t e:1; 
    uint32_t f:1; 
    uint32_t g:3; 
    uint32_t h:1; 
    uint32_t i:1; 
    uint32_t j:3; 
    uint32_t k:3; 
    uint32_t l:1; 
    uint32_t m:1; 
    uint32_t n:1; 
    uint32_t o:1; 
    uint32_t p:3; 
    uint32_t q:2; 
    uint32_t r:1; 
    uint32_t s:1; 
    uint32_t t:2; 
    //4 bytes ends here 

    // shouldn't this start at 5th byte ?? 
    uint16_t u; 

    uint16_t v:13; 
    uint16_t w:3; 

    uint16_t x; 

    uint16_t y:13; 
    uint16_t z:3; 
}; 

int main() 
{ 
    struct non_alligned_struct obj1; 
    void *ptr1 = &obj1; 
    void *ptr2 = &(obj1.u); 
    printf("ptr1: %p, ptr2: %p, ptr2 - ptr1: %d\n", ptr1, ptr2, ptr2 - ptr1); 
    return 0; 
} 

Sortie: ptr1: 0x7fff3216a620, ptr2: 0x7fff3216a626, ptr2 - ptr1: 6

Question: Pourquoi ptr2 - ptr1 devrait être 6. Selon mes calculs, cela aurait dû être 5. De plus, la structure est de 13 octets, donc 4 octets sont alignés et le remplissage est fait de façon bizarre. Je vérifié en donnant des valeurs aléatoires pour les variables membres et je constate que le rembourrage est réalisé en suivant endroits gras

00000000: 01 22 31 10 67 fe 86 01 fe ff 86 01

+0

ptr2-ptr1 est égal à 6 ... – DigitalNinja

+0

En MSVC si je joins le 'struct' avec' #pragma pack (push, 1) 'et' #pragma pack (pop) 'il donne le résultat attendu' 5' , autrement '8'. J'ai dû changer les pointeurs 'void *' en 'char *' car l'arithmétique du pointeur sur les types 'void *' est définie par l'implémentation. –

+0

Violation de contrainte faisant de l'arithmétique sur 'void *' s. Votre compilateur était obligé d'émettre un diagnostic pour cette erreur. – EOF

Répondre

1

L'alignement des champs de bits est défini par l'implémentation. Votre implémentation semble utiliser 1 ou (éventuellement 2) octets d'alignement pour le champ uint32_t. Par conséquent, flag occupe l'octet 0 et le champ de bit occupe les octets 1..4 ou 2..5. Dans le premier cas, u utilise par défaut un alignement de 2 octets qui le place aux octets 6..7, et dans le dernier cas, 6..7 est déjà le prochain emplacement disponible.

+0

De l'hexagone en gras dans l'OP, je dirais que le bit-field est aligné sur 1 octet, et le champ 'u' est aligné sur 2 octets, comme prévu pour un' uint16_t'. – rodrigo

1

Question: Pourquoi ptr2 - ptr1 devrait être 6. Selon mon calcul, il aurait dû 5.

C permet d'insérer les mises en œuvre entre le rembourrage et après éléments struct en tout montant et tout arrangement qu'ils choisir. De plus, il ne spécifie pas comment les champs de bits sont alloués aux unités de stockage adressables, ni quelle taille peuvent être les unités de stockage adressables auxquelles ils sont affectés. En particulier, le type déclaré d'un champ de bits ne dit rien à ce sujet en ce qui concerne la norme.

En fin de compte, par conséquent, vous pouvez calculer le nombre de bits requis pour représenter les membres de la structure avant u, mais vous ne peut pas calculer ce que le décalage de u devrait être fondée que sur la déclaration de la structure contenant.

En pratique, il n'est pas surprenant de voir u positionné à un décalage pair par rapport au début de la structure. Il s'ensuit qu'il y a un certain remplissage dans la représentation de la structure, mais il est difficile de déterminer exactement où ce remplissage est difficile, car vous ne pouvez pas prendre l'adresse de calcul d'un champ de bits.