2011-12-21 12 views
9

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 cambio de bits o el enmascaramiento para lograr esto? Puedo acceder poco a poco, pero no dos bits de una vez?Bits de acceso en un carácter en C

Respuesta

12

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

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

Su mejor opción es utilizar el enmascaramiento de bits, como se había mencionado. Algo como esto debe hacer el truco:

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

Aquí, suponía que quería aislar el 11 del "0011". Si solo necesita los dos bits de orden más bajo, x & 0x03 funcionaría, como lo ha demostrado dasblinkenlight. – zje

9

Este es un ejemplo para acceder a ella poco a poco:

#include <stdio.h> 
int main() 
{ 
    char byte = 0x37; 
    int i; 

    for(i = 7; 0 <= i; i --) 
     printf("%d\n", (byte >> i) & 0x01); 

    return 0; 
} 
5

También puede utilizar campos de bits para hacer esto. La parte mala de los campos de bits es que exactamente cómo funcionan depende de algún modo del compilador, pero si no necesitas transferir el código a muchas arquitecturas, quizás esté bien.

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

#include <assert.h> 
#include <stdio.h> 

#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); 
    m.b = 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); 

    m.b = 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(m.b == 0x71); 
    printf("m.b is: 0x%02x\n", m.b); 

    return 0; 
} 

la Unión está allí, así que se puede acceder a él como un byte completo o acceder a él por los campos de bits. #pragma pack(1) está ahí para asegurarse de que los campos de bits se empaquetan en un byte, sin bits de "relleno" adicionales. (Como dije antes, confía en los detalles de implementación cuando usa campos de bits.)

Pero vea qué sencillo y limpio es acceder a los bits que desea. Puede escribir en un byte completo y leer los bits que desee, o escribir los bits que desee y leer todo el byte.

Si vas a utilizar un código como este, siempre es una buena idea tener algunas afirmaciones que aseguren que está funcionando.

Si no va a utilizar campos de bits, le sugiero que defina una función que realice su cambio y enmascaramiento para usted, para asegurarse de que no se equivoca. Tal vez algo como esto:

#include <limits.h> 


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

Se pasa de un valor y, a continuación, que se mordió posición que desee bits de, y la cantidad de bits que desea. Así que para agarrar 6 bits a partir de la posición de bit 2, con un valor de prueba de 0x71 que se podría llamar:

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

Si no te gusta la tabla de consulta, y desea que el código más pequeño para hacer esto, usted puede utilizar:

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

Es necesario asegurarse de que los bits de máscara se declaran unsigned porque si llevan la firma, la operación de desplazamiento a la derecha firmará a extender.

Si declara esta última versión de la función como en línea, la coloca en archivos de encabezado y la llama con valores constantes para i_bit y c_bits, se compilará hasta el código mínimo para resolver el problema. (Por ejemplo, si i_bit es 0, el compilador sabe que >> 0 no hace nada y no generará ese código. Y si el compilador conoce c_bits como una constante, puede hacer todo el trabajo de cambiar mask_bits en tiempo de compilación.) Pero necesitará asegurarse de que está utilizando una versión de assert() que se compila en cero en su compilación de lanzamiento, o bien use su propia macro ASSERT() y haga que su compilación de macro quede en nada.

2

Esta es la función más fácil de usar, no quiero que otros luchan por un largo tiempo antes de conseguir 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

Cuestiones relacionadas