Existe-t-il un moyen d’accéder à des éléments individuels avec un syndicat?

J’écris un programme en C. Je veux une variable à laquelle je peux accéder en tant que caractère, mais je peux aussi accéder aux bits spécifiques de. Je pensais pouvoir utiliser un syndicat comme celui-ci …

typedef union { unsigned char status; bit bits[8]; }DeviceStatus; 

mais le compilateur n’aime pas ça. Apparemment, vous ne pouvez pas utiliser de bits dans une structure. Alors, que puis-je faire à la place?

    Bien sûr, mais vous voulez réellement utiliser une structure pour définir les bits comme ceci

     typedef union { struct { unsigned char bit1 : 1; unsigned char bit2 : 1; unsigned char bit3 : 1; unsigned char bit4 : 1; unsigned char bit5 : 1; unsigned char bit6 : 1; unsigned char bit7 : 1; unsigned char bit8 : 1; }u; unsigned char status; }DeviceStatus; 

    Ensuite, vous pouvez accéder à DeviceStatus ds; vous pouvez accéder à ds.u.bit1 . En outre, certains compilateurs vous autoriseront à avoir des structures anonymes dans une union, de sorte que vous ne pouvez accéder qu’à ds.bit1 si vous omettez le u à partir de la typedef.

    Vous avez deux possibilités. On pourrait simplement utiliser les mathématiques booléennes pour comprendre les points suivants:

     int bit0 = 1; int bit1 = 2; int bit2 = 4; int bit3 = 8; int bit4 = 16; int bit5 = 32; int bit6 = 64; int bit7 = 128; if (status & bit1) // whatever... 

    Une autre consiste à utiliser des champs de bits:

     struct bits { unsigned bit0 : 1; unsigned bit1 : 1; unsigned bit2 : 1; // ... }; typedef union { unsigned char status; struct bits bits; } status_byte; some_status_byte.status = whatever; if (status_byte.bits.bit2) // whatever... 

    Le premier est (du moins sans doute) plus portable, mais quand vous avez affaire à des bits d’état, il y a de fortes chances que le code ne soit même pas légèrement portable de toute façon, alors vous ne vous en souciez peut-être pas beaucoup …

    Comme cela a déjà été dit, vous ne pouvez pas adresser de mémoire plus petite qu’un octet en C. Je voudrais écrire une macro:

     #define BIT(n) (1 << n) 

    et l'utiliser pour accéder aux bits. Ainsi, votre access est le même, quelle que soit la taille de la structure à laquelle vous accédez. Vous écririez votre code comme:

     if (status & BIT(1)) { // Do something if bit 1 is set } elseif (~status | BIT(2) { // Do something else if bit 2 is cleared } else { // Set bits 1 and 2 status |= BIT(1) | BIT(2) // Clear bits 0 and 4 status &= ~(BIT(0) | BIT(4)) // Toggle bit 5 status ^= BIT(5) } 

    Cela vous permet d’avoir un access proche du système proposé, qui utiliserait [] au lieu de ().

     typedef union { unsigned char status; struct bitFields { _Bool bit0 : 1; _Bool bit1 : 1; _Bool bit2 : 1; _Bool bit3 : 1; _Bool bit4 : 1; _Bool bit5 : 1; _Bool bit6 : 1; _Bool bit7 : 1; } bits; }DeviceStatus; 

    La plus petite unité adressable en C est toujours un octet (appelé char en C). Vous ne pouvez pas accéder à un bit directement. Le moyen le plus proche d’accéder aux bits serait de définir un type de données appelé bitpointer et de définir des fonctions ou des macros pour ce dernier:

     #include  typedef struct bitpointer { unsigned char *pb; /* pointer to the byte */ unsigned int bit; /* bit number inside the byte */ } bitpointer; static inline bool bitpointer_isset(const bitpointer *bp) { return (bp->pb & (1 << bp->bit)) != 0; } static inline void bitpointer_set(const bitpointer *bp, bool value) { unsigned char shifted = (value ? 1 : 0) << bp->bit; unsigned char cleared = *bp->pb &~ (1 << bp->bit); *(bp->pb) = cleared | shifted; } 

    Je déconseille les unions, car elles sont définies par l’implémentation, qu’elles soient remplies de msb à lsb ou de lsb à msb (voir ISO C99, 6.7.2.1p10).

    Vous pouvez le faire en plaçant les bits dans une structure à l’intérieur de l’union, mais cela peut ou non fonctionner, en fonction de votre implémentation. La définition de langage ne spécifie pas dans quel ordre les bits séparés seront mis en correspondance avec les bits du caractère unsigned char ; pire, cela ne garantit même pas que les bits chevaucheront le caractère unsigned char (le compilateur peut décider de placer les bits séparés vers le côté le plus significatif du mot et le caractère unsigned char vers le côté le moins significatif ou vice versa).

    La technique habituelle dans votre situation consiste à utiliser des opérations au niveau des bits. Définissez des constantes nommées d’après la signification des bits, par exemple,

     #define FLAG_BUSY 0x01 #define FLAG_DATA_AVAILABLE 0x02 #define FLAG_TRANSMISSION_IN_PROGRESS 0x04 ... #define FLAG_ERROR 0x80 

    Ensuite, pour lire et écrire des bits individuels:

     if (status & FLAG_BUSY) ... /* test if the device is busy */ status &= ~FLAG_ERROR; /* turn off error flag */ status |= FLAG_TRANSMISSION_IN_PROGRESS /* turn on transmission-in-progress flag */