2015-10-07 1 views
0

J'utilise typedefs de cette forme pour simplifier l'accès aux registres du microprocesseur et les champs de bits en leur sein.Pourquoi ce typedef donne-t-il une valeur sizeof() plus grande que prévu?

typedef union 
    { 
    uint8_t  u8Byte;   ///< REG_8 as unsigned byte 
    int8_t   i8Byte;   ///< REG_8 as signed byte 
    struct 
    { 
     unsigned b0:1;    ///< Bit 0 of REG_8 type 
     unsigned b1:1;    ///< Bit 1 of REG_8 type 
     unsigned b2:1;    ///< Bit 2 of REG_8 type 
     unsigned b3:1;    ///< Bit 3 of REG_8 type 
     unsigned b4:1;    ///< Bit 4 of REG_8 type 
     unsigned b5:1;    ///< Bit 5 of REG_8 type 
     unsigned b6:1;    ///< Bit 6 of REG_8 type 
     unsigned b7:1;    ///< Bit 7 of REG_8 type 
    }; 
    } REG_8; 

Malheureusement, sizeof(REG_8) renvoie 2 au lieu des attendus 1. Des définitions similaires pour les tailles de retour REG_16 et REG_32 de 2 et 4, comme prévu. sizeof(uint8_t) et sizeof(int8_t) renvoient 1, comme prévu.

Le type fonctionne comme prévu. Par exemple,

REG_8 a; 
a.u8Byte = 4; 

donne a.b2 une valeur de 1, donc il n'y a pas de problème d'alignement.

La suppression de struct donne une valeur de sizeof de 1, donc il semble qu'il y ait un problème de remplissage, mais si oui, pourquoi?

Quelqu'un peut-il expliquer cela? J'utilise le compilateur Microchip XC16 (basé sur GCC) ciblant un processeur 16 bits.

+0

Je pense que votre machine 16 bits aurait 1 octet de rembourrage pour votre une union d'octets, en raison à l'adressage strict d'alignement de données. Ceci est une supposition, car je ne suis pas familier avec la machine/compilateur. – IanGabes

+1

@IanGabes Sur cette machine 16 bits, les mots doivent en effet être alignés sur les adresses paires, mais la machine peut accéder aux octets à n'importe quelle adresse (c.-à-d. Aucune exigence d'alignement) – EBlake

Répondre

2

Probablement sizeof (unsigned) = 2 sur votre machine, de sorte que tout champ de bits "non signé" occupe au moins 2 octets. Le remplacement non signé par uint8_t devrait apporter sizeof (REG_8) à 1.

Voir aussi cette question: How is the size of a struct with Bit Fields determined/measured?

+0

sizeof (unsigned) is 2, isn ' t le: 1 qualificatif remplace cela pour les membres de la structure? De plus, si le membre b7 obtient 2 octets, alors l'union ne devrait-elle pas atteindre 3 octets (2 + 7/8 arrondi)? – EBlake

+0

les membres struct occuperont chacun 1 bit d'un non signé. (Je ne comprends pas la deuxième partie de votre commentaire - comment déclareriez-vous b7?) – twin

+0

Si vous déclarez b7: 16 non signé, la structure a besoin de deux non-signés, donc devrait avoir la taille 4 – twin

0

Il semble que @twin a eu l'idée correcte, bien que j'ai aussi trouvé une autre solution. Deux alternatives qui donnent à la sizeof(REG_8) == 1 sont attendues:

typedef union 
    { 
    uint8_t  u8Byte;   ///< REG_8 as unsigned byte 
    int8_t   i8Byte;   ///< REG_8 as signed byte 
    struct 
    { 
     unsigned b0:1;    ///< Bit 0 of REG_8 type 
     unsigned b1:1;    ///< Bit 1 of REG_8 type 
     unsigned b2:1;    ///< Bit 2 of REG_8 type 
     unsigned b3:1;    ///< Bit 3 of REG_8 type 
     unsigned b4:1;    ///< Bit 4 of REG_8 type 
     unsigned b5:1;    ///< Bit 5 of REG_8 type 
     unsigned b6:1;    ///< Bit 6 of REG_8 type 
     unsigned b7:1;    ///< Bit 7 of REG_8 type 
    } __attribute__((packed)); 
    } REG_8; 

... ou ...

typedef union 
    { 
    uint8_t  u8Byte;   ///< REG_8 as unsigned byte 
    int8_t   i8Byte;   ///< REG_8 as signed byte 
    struct 
    { 
     uint8_t b0:1;    ///< Bit 0 of REG_8 type 
     uint8_t b1:1;    ///< Bit 1 of REG_8 type 
     uint8_t b2:1;    ///< Bit 2 of REG_8 type 
     uint8_t b3:1;    ///< Bit 3 of REG_8 type 
     uint8_t b4:1;    ///< Bit 4 of REG_8 type 
     uint8_t b5:1;    ///< Bit 5 of REG_8 type 
     uint8_t b6:1;    ///< Bit 6 of REG_8 type 
     uint8_t b7:1;    ///< Bit 7 of REG_8 type 
    }; 
    } REG_8;