2016-02-15 1 views
0

Accroché geeksforgeeks sur les bitfields, ont trouvé cet exemple:Mixing bitfields dans les structures

#include <stdio.h> 

struct test { 
    unsigned int x; 
    long int y : 33; 
    unsigned int z; 
}; 

int main() { 
    struct test t; 
    unsigned int *ptr1 = &t.x; 
    unsigned int *ptr2 = &t.z; 
    printf("%d", ptr2 - ptr1); 
    return 0; 
} 

En conséquence, la production est 4. Mais pourquoi? x occupe 4 octets, y - 8, et z - 4. Différence dans les adresses x et z doit être 8?

+3

La différence entre deux pointeurs n'est pas comptée en octets, mais dans le type de point indiqué par les pointeurs. De plus, 'type' est aligné sur l'alignement du membre le plus aligné (probablement' long int'), et '& test.x == & test', donc si' sizeof (unsigned)! = Sizeof (long int) ', il y a est un espace d'alignement (remplissage) entre 'test.x' et' test.y', à condition que l'implémentation accepte même les champs de type 'long int'. – EOF

+2

Je ne cesse d'entendre parler de ce "geekforgeeks" dans chaque message qui contient un comportement affreux, mal spécifié, code non-sens. Je pense vraiment que vous devriez éviter ce site, il ne semble pas qu'ils sachent de quoi ils parlent. – Lundin

+0

Lundin: Peut-être que je peux être d'accord, je l'ai trouvé il y a quelques jours ... Mais de toute façon, cet exemple "cheval sphérique dans le vide" difficile, m'a lutté :) – artsin

Répondre

4

Ce code n'a pas de comportement déterminable. Il est impossible de prédire son issue sans un compilateur très spécifique.

Il contient le comportement défini par l'implémentation suivante (citations de l'annexe J de la norme):

- Que ce soit un « bit-champ » int « plaine » est traité comme un entier signé -champ de bits ou en tant que champ de bits int non signé (6.7.2, 6.7.2.1).

- Types de champs binaires autorisés autres que _Bool, signés int et non signés int (6.7.2.1).

- Indique si un champ de bits peut chevaucher une limite d'unité de stockage (6.7.2.1).

- L'ordre d'attribution des champs de bits dans une unité (6.7.2.1).

- L'alignement des éléments non-binaires des structures (6.7.2.1). Ce ne devrait présenter aucun problème à moins que les données binaires écrites par une implémentation soient lues par un autre.

La deuxième remarque implique également que le compilateur doit avoir une extension non standard. En plus de cela, le code dépend également de l'endianess et vous ne pouvez pas savoir quels bits dans le champ binaire sont le MSB et le LSB.

+0

Plus pertinent: Projet de norme C11 '6.5.6 Opérateurs d'additif, section 9 Lorsque deux pointeurs sont soustraits, les deux points doivent pointer vers les éléments du même objet tableau, ou dépasser le dernier élément de l'objet tableau; [...] '. Bien que '6.5.8 Opérateurs relationnels, section 5 [...] Si les objets pointés sont des membres du même objet agrégat, les pointeurs vers les membres de la structure déclarés plus tard comparent plus que les pointeurs aux membres déclarés plus tôt dans la structure [...] 'rend * probable * aucune implémentation réelle ne va échouer ce code. – EOF

+0

De même, 'sizeof (int)' et 'sizeof (long)' sont également définis par l'implémentation. Nous pouvons voir ici que ce code a été compilé avec un compilateur non-MSVC 64 bits parce que 'sizeof (long)' est 8. Avec MSVC ou les compilateurs 32 bits, 'sizeof (long)' est 4. – ElderBug

+0

@EOF Oui, je Je suis sûr que l'on pourrait écrire un essai complet sur la façon dont ce code pourrait/va mal tourner. N'écrivez pas un tel code non-sens et il n'y aura pas de problèmes. – Lundin