Bits de acceso en un char en C

Tengo un número hexadecimal 0x37 y su representación binaria es 0011 0111. ¿Cómo accedo a los primeros 2 bits de la representación binaria que es “11”? ¿Cómo uso el desplazamiento de bits o el enmascaramiento para lograr esto? ¿Puedo acceder poco a poco pero no dos bits a la vez?

Si usted & su número con 0x03, obtendrá los últimos dos bits.

 char c = 0x37; char mask = 0x03; char lastTwo = c & mask; 

Aquí hay una muestra para acceder poco a poco:

 #include  int main() { char byte = 0x37; int i; for(i = 7; 0 <= i; i --) printf("%d\n", (byte >> i) & 0x01); return 0; } 

También podría utilizar campos de bits para hacer esto. Lo malo de los campos de bits es que la forma exacta en que funcionan depende del comstackdor, pero si no necesita portar su código a muchas architectures, tal vez esté bien.

Aquí hay un ejemplo, escrito en una computadora Ubuntu Linux y probado con GCC.

 #include  #include  #pragma pack(1) typedef struct { unsigned int low2: 2; // 2 bits of the byte unsigned int high6: 6; // 6 more bits of the byte } MYBYTE; typedef union { MYBYTE mybyte; unsigned char b; } MYUNION; main() { MYUNION m; assert(sizeof(m) == 1); mb = 0x03; assert(m.mybyte.low2 == 0x03); assert(m.mybyte.high6 == 0x00); printf("low2 of 0x03 is: %u\n", m.mybyte.low2); printf("high6 of 0x03 is: %u\n", m.mybyte.high6); mb = 0xff; printf("low2 of 0x03 is: %u\n", m.mybyte.low2); printf("high6 of 0x03 is: %u\n", m.mybyte.high6); assert(m.mybyte.low2 == 0x03); assert(m.mybyte.high6 == 0x3f); m.mybyte.high6 = 0x1c; m.mybyte.low2 = 0x01; assert(mb == 0x71); printf("mb is: 0x%02x\n", mb); return 0; } 

La unión está ahí para que podamos acceder a ella como un byte completo, o acceder a ella mediante campos de bits. #pragma pack(1) está ahí para asegurarse de que los campos de bits se reduzcan a un byte, sin bits de “relleno” adicionales allí. (Como dije antes, está confiando en los detalles de la implementación cuando usa campos de bits).

Pero mira lo simple y limpio que es acceder a los bits que deseas. Puede escribir en un byte completo y leer los bits que desee, o escribir en los bits que desee y leer todo el byte.

Si va a utilizar un código como este, siempre es una buena idea tener algunas afirmaciones que se aseguren de que funcione.

Si no va a utilizar campos de bits, le sugiero que defina una función que haga el cambio y el enmascaramiento por usted, para asegurarse de no estropearse. Tal vez algo como esto:

 #include  static unsigned int _bit_masks[] = { 0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff, 0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff, 0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff, 0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff, }; #define MIN(a, b) \ ((a) < (b) ? (a) : (b)) unsigned int bits(unsigned int x, unsigned int i_bit, unsigned int c_bits) { assert(UINT_MAX >= 4294967295U); // unsigned int must be at least 32-bit assert(i_bit <= 31); if (i_bit > 31) return 0; c_bits = MIN(c_bits, 32 - i_bit); // shift-and-mask to grab the requested bits, and return those bits return (x >> i_bit) & _bit_masks[c_bits]; } 

Pasas un valor, luego de qué posición de bit quieres bits y cuántos bits quieres. Entonces, para capturar 6 bits a partir de la posición de bit 2, con un valor de prueba de 0x71 puede llamar:

 x = bits(0x71, 2, 6); // x is set to 0x1c 

Si no te gusta la tabla de búsqueda, y quieres que el código más pequeño haga esto, puedes usar:

 unsigned int bits(unsigned int x, unsigned int i_bit, unsigned int c_bits) { const unsigned int mask_bits = 0xffffffff; assert(UINT_MAX >= 4294967295U); // unsigned int must be at least 32-bit assert(i_bit <= 31); if (i_bit > 31) return 0; c_bits = MIN(c_bits, 32 - i_bit); // shift-and-mask to grab the requested bits, and return those bits return (x >> i_bit) & (mask_bits >> (32 - c_bits)); } 

Debe asegurarse de que los bits de la máscara se declaren unsigned porque, si están firmados, la operación de cambio a la derecha se ampliará.

Si declara esta última versión de la función como en línea, i_bit en i_bit de i_bit y la c_bits con valores constantes para i_bit y c_bits , se comstackrá hasta el código mínimo para resolver el problema. (Por ejemplo, si i_bit es 0, el comstackdor sabe que >> 0 no hace nada y simplemente no generará ese código. Y si el comstackdor conoce c_bits como una constante, puede hacer todo el trabajo de cambiar mask_bits al comstackr tiempo.) Pero tendrá que asegurarse de que está utilizando una versión de assert() que comstack hasta el final en su comstackción de la versión, o bien use su propia macro ASSERT() y haga que la macro se compile de la nada.

Lo mejor que puedes hacer es utilizar el enmascaramiento de bits, como mencionaste. Algo como esto debería hacer el truco:

 x = 0x37; y = x&0x30; //Mask out the first two bits of the higher nibble y = y>>4; 

Esta es la función más fácil de usar, no quiero que otros luchen durante mucho tiempo antes de obtener algo similar a esto:

 char get_bits(char a, char no_of_bits) { return a & ((no_of_bits << 1) - 1); } char a = 0x37; char b = get_bits(a, 2); 

Espero que ayude a alguien en el futuro.