2010-08-16 21 views
16

Estoy escribiendo un programa en C. Quiero una variable a la que pueda acceder como char, pero también puedo acceder a los bits específicos de. Estaba pensando que podría usar una unión como esta ...¿Hay alguna manera de acceder a los bits individuales con una unión?

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

pero al compilador no le gusta esto. Aparentemente no puedes usar bits en una estructura. Entonces, ¿qué puedo hacer?

Respuesta

18

Claro, pero en realidad se desea utilizar una estructura para definir los bits como esto

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; 

A continuación, puede acceder a DeviceStatus ds; puede acceder ds.u.bit1. Además, algunos compiladores le permitirán tener estructuras anónimas dentro de una unión, de modo que solo puede acceder al ds.bit1 si omite u de typedef.

+0

C99 6.7.2.1/10: "Una implementación puede asignar cualquier unidad de almacenamiento direccionable lo suficientemente grande como para contener un campo de bits". No es necesario asignar un solo 'char', por lo que es posible que no se produzca ningún aliasing. Además, la norma exige estructuras anónimas dentro de la unión. – Potatoswatter

+0

¿Tiene que nombrar la estructura? – jjxtra

1
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; 
+0

¿La especificación C99 define un tamaño para el tipo _Bool? Eché un vistazo rápido y no vi nada obvio. – torak

+0

@torak: por definición, cualquier tipo es al menos tan ancho como un 'char'. Pero este no es el punto aquí ya que estos son bitfields. El compilador en realidad * podría * colocar los campos 'bitX' sobre los bits de estado, pero no hay garantía para ello. –

+0

Puede usar cualquier tipo integral de _Bool para el tipo de campo de bits, siempre que tenga al menos ese número de bits. Dado que el tamaño utilizado aquí es de 1 bit, no hay ningún tipo de bit permitido que no sirva. –

3

Tiene un par de posibilidades. Una de ellas sería simplemente usar las matemáticas de Boole para llegar a los bits:

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... 

Otra es utilizar campos 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... 

La primera es (al menos posiblemente) más portátiles, pero cuando estás Al tratar con bits de estado, es probable que el código no sea ni siquiera ligeramente portátil de todos modos, por lo que puede no importarle demasiado ...

+0

¿'sin signo' corresponde a un tipo de datos más grande que un' char'? Esto haría 'sizeof (char) torak

+1

@Jerry Coffin: Solo se garantiza que su primera versión usará los bits de estado. En la 'unión', los campos individuales 'bitX' pueden completarse como agradables para el compilador. –

+0

@torak: Sí, el podría. Si eso es un problema para ti, entonces probablemente quieras hacer que los campos sean todos 'char sin signo '. –

0

La unidad más pequeña que puede direccionarse en C siempre es un byte (llamado char en C) No puedes acceder a un bit directamente. La forma más cercana para llegar a acceder a los bits sería definir un tipo de datos llamado bitpointer y definir algunas funciones o macros para ello:

#include <stdbool.h> 

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; 
} 

recomiendo contra los sindicatos, ya que es bit más significativo si se llenan definido por la implementación -to-lsb o lsb-to-msb (ver ISO C99, 6.7.2.1p10).

0

Puede hacerlo colocando los bits en una estructura dentro de la unión, pero puede funcionar o no, según su implementación. La definición del lenguaje no especifica en qué orden los bits separados se emparejarán con los bits del unsigned char; peor aún, ni siquiera garantiza que los bits se superpongan con el unsigned char (el compilador puede decidir colocar los bits separados hacia el lado más significativo de una palabra y el unsigned char hacia el lado menos significativo o viceversa).

La técnica habitual en su caso es utilizar operaciones bit a bit. Definir constantes con nombre después de que el significado de los bits, por ejemplo,

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

Luego de leer y escribir bits individuales:

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 */ 
2

Como ya se ha dicho, no se puede abordar de memoria más pequeña que un byte en C. Escribiría una macro:

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

y la usaré para acceder a los bits. De esta forma, su acceso es el mismo, independientemente del tamaño de la estructura a la que está accediendo.Se podría escribir el código como:

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) 
} 

Esto le proporcionará acceso cerca de su sistema propuesto, que utilizaría [] en lugar de().

Cuestiones relacionadas