2017-09-28 1 views
2

Voici les instructions:J'ai besoin d'écrire un programme C qui utilise une structure de l'Union pour définir les bits d'un int

Définir un WORD_T struct de données Union pour un nombre entier de uint16_t de sorte qu'une valeur peut être affectée à un WORD_T entier de trois façons: (1) Pour affecter la valeur à chaque bit de l'entier, (2) Pour affecter la valeur à chaque octet de l'entier, (3) Affecter directement la valeur à l'entier. Je sais que je dois faire quelque chose de différent avec cette première structure, mais je suis assez perdu en général. Voici ce que j'ai:

#include <stdio.h> 
#include <unistd.h> 
#include <stdlib.h> 
#include <sys/types.h> 

#define BIT(n) (1 << n) 
#define BIT_SET(var, mask) (n |= (mask)) 
#define BIT_CLEAR(var, mask) (n &= ~(mask)) 
#define BIT_FLIP(var, mask) (n ^= (mask)) 

union WORD_T{ 
    struct{ 
     uint16_t integerVar:16 

    }; 
    struct{ 
     unsigned bit1:0; 
     unsigned bit2:0; 
     unsigned bit3:0; 
     unsigned bit4:0; 
     unsigned bit5:0; 
     unsigned bit6:0; 
     unsigned bit7:0; 
     unsigned bit8:0; 
     unsigned bit9:0; 
     unsigned bit10:0; 
     unsigned bit11:0; 
     unsigned bit12:0; 
     unsigned bit13:0; 
     unsigned bit14:0; 
     unsigned bit15:0; 
     unsigned bit16:0; 
    }; 

    void setIndividualBit(unsigned value, int bit) { 
     mask = BIT(value) | BIT(bit); 
     BIT_SET(n, mask); 
    } 
}; 
+0

' unsigned bit1: 0; 'signifie que 0 bit est grand, cela n'a pas de sens. Voulez-vous dire 'unsigned bit1: 1;'? – mch

+0

Je pense que mch a raison - 'bit1: 0' dit" utiliser zéro bits des unsigned ", où' bit1: 1' dit "use one bit" – theGleep

+1

Pour éviter certains problèmes d'implémentation, utilisez '#define BIT (n) (1u << n) '(ajouter' u') – chux

Répondre

2

est ici la définition du syndicat:

union WORD_T 
{ 
    uint16_t word; 

    struct 
    { 
     uint8_t byte0; 
     uint8_t byte1; 
    }; 

    struct 
    { 
     uint8_t bit0:1; 
     uint8_t bit1:1; 
     uint8_t bit2:1; 
     uint8_t bit3:1; 
     uint8_t bit4:1; 
     uint8_t bit5:1; 
     uint8_t bit6:1; 
     uint8_t bit7:1; 
     uint8_t bit8:1; 
     uint8_t bit9:1; 
     uint8_t bit10:1; 
     uint8_t bit11:1; 
     uint8_t bit12:1; 
     uint8_t bit13:1; 
     uint8_t bit14:1; 
     uint8_t bit15:1; 
    }; 
}; 

Pour attribuer aux composants individuels, faire quelque chose de semblable à ce qui suit:

union WORD_T data; 

data.word = 0xF0F0; // (3) Assign to entire word 

data.byte0 = 0xAA; // (2) Assign to individual byte 

data.bit0 = 0; // (1) Assign to individual bits 
data.bit1 = 1; 
data.bit2 = 1; 
data.bit2 = 0; 
+0

quand serait byte1 être utilisé? –

+1

@DouglasAdolph la définition de byte0 comme dans mon exemple écrase seulement les 8 bits inférieurs de l'emplacement de mémoire de 16 bits. Utilisez byte1 pour définir les 8 bits supérieurs du même emplacement de mémoire de 16 bits. –

3

Le problème le plus évident est que :0 signifie "un champ de bit de zéro bits" qui n'a aucun sens. Vous devriez changer ceci à 1 et ensuite vous pouvez assigner des bits individuels à travers le code comme the_union.the_struct.bit1 = 1;.

Ce format est une alternative aux macros set/clear que vous avez écrites.

Votre syndicat devrait ressembler à:

typedef union 
{ 
    uint16_t word; 
    uint8_t byte[2]; 
    struct{ 
    uint16_t bit1:1; 
    ... 

Cependant. C'est une très mauvaise idée et votre professeur devrait savoir mieux que de donner de telles tâches. Les champs de bits en C sont un sac de vers - ils sont très mal spécifiés par la norme. Problèmes:

  • Vous ne pouvez pas savoir quel bit est le MSB, il n'est pas défini.
  • Vous ne pouvez pas savoir s'il y aura des bits/octets de remplissage quelque part.
  • Vous ne pouvez même pas utiliser uint16_t ou uint8_t car les zones de bits ne sont spécifiées que pour fonctionner avec int.

Et ainsi de suite. En outre, vous devez faire face à l'endianness et l'alignement. Voir Why bit endianness is an issue in bitfields?. Pour l'essentiel, le code utilisant des champs binaires comme celui-ci dépendra fortement du compilateur spécifique. Ce sera complètement non portable.

Tous de ces problèmes pourraient être évités en laissant tomber le champ de bits et utiliser des opérateurs sur un uint16_t au niveau du bit au lieu, comme vous l'avez fait dans vos macros. Avec les opérateurs bit à bit uniquement, votre code deviendra déterministe et 100% portable. Vous pouvez même les utiliser pour esquiver l'endianess, en utilisant des changements de bits. `