¿Cómo extraigo ‘n’ bits específicos de un entero sin signo de 32 bits en C?

¿Podría alguien decirme cómo extraer ‘n’ bits específicos de un entero sin signo de 32 bits en C.

Por ejemplo, digamos que quiero los primeros 17 bits del valor de 32 bits; ¿Qué es lo que debo hacer?
Supongo que debo usar el operador de módulo y lo probé y pude obtener los últimos 8 bits y los últimos 16 bits como

unsigned last8bitsvalue=(32 bit integer) % 16 unsigned last16bitsvalue=(32 bit integer) % 32 

¿Es esto correcto? ¿Hay una manera mejor y más eficiente de hacer esto?

Si desea n bits específicos, primero puede crear una máscara de bits y luego AND con su número para tomar los bits deseados.

Función simple para crear una máscara de bit a bit b.

 unsigned createMask(unsigned a, unsigned b) { unsigned r = 0; for (unsigned i=a; i<=b; i++) r |= 1 << i; return r; } 

Debe comprobar que a <= b.

Si desea que los bits 12 a 16 llame a la función y luego simplemente & (lógico AND) r con su número N

 r = createMask(12,16); unsigned result = r & N; 

Si quieres puedes cambiar el resultado. Espero que esto ayude

En lugar de pensar en eso como “extraer”, me gusta pensar en “aislar”. Una vez que los bits deseados están aislados, puede hacer lo que quiera con ellos.

Para aislar cualquier conjunto de bits, aplique una máscara AND.

Si desea los últimos X bits de un valor, hay un truco simple que se puede utilizar.

 unsigned mask; mask = (1 << X) - 1; lastXbits = value & mask; 

Si desea aislar una serie de X bits en medio de 'valor' comenzando en 'startBit' ...

 unsigned mask; mask = ((1 << X) - 1) << startBit; isolatedXbits = value & mask; 

Espero que esto ayude.

El módulo funciona para obtener los bits inferiores (solo), aunque creo que value & 0x1ffff expresa “tome los 17 bits inferiores” más directamente que el value % 131072 , por lo que es más fácil de entender que hacerlo.

Los 17 bits superiores de un valor sin signo de 32 bits serían value & 0xffff8000 (si los quiere en su posición superior), o value >> 15 si desea los 17 bits superiores del valor en los 17 bits inferiores del resultado.

Si necesita los X últimos bits de su entero, use una máscara binaria :

 unsigned last8bitsvalue=(32 bit integer) & 0xFF unsigned last16bitsvalue=(32 bit integer) & 0xFFFF 

Bitwise Y su entero con la máscara que tiene exactamente esos bits establecidos que desea extraer. Luego desplace el resultado hacia la derecha para reposicionar los bits extraídos si lo desea.

 unsigned int lowest_17_bits = myuint32 & 0x1FFFF; unsigned int highest_17_bits = (myuint32 & (0x1FFFF << (32 - 17))) >> (32 - 17); 

Edición: Este último reposiciona los 17 bits más altos como los 17 más bajos; esto puede ser útil si necesita extraer un número entero de “dentro” de uno más grande. Puede omitir el cambio a la derecha ( >> ) si esto no se desea.

Hay una sola instrucción BEXTR (extracto de campo de bits (con registro)) x86 en las CPU Intel y AMD y UBFX en ARM. Hay funciones intrínsecas como _bextr_u32() (el enlace requiere inicio de sesión) que permiten invocar esta instrucción explícitamente.

Implementan (source >> offset) & ((1 << n) - 1) código C: obtienen n bits continuos de la source comenzando en el bit de offset . Aquí hay una definición de función completa que maneja casos de borde:

 #include  unsigned getbits(unsigned value, unsigned offset, unsigned n) { const unsigned max_n = CHAR_BIT * sizeof(unsigned); if (offset >= max_n) return 0; /* value is padded with infinite zeros on the left */ value >>= offset; /* drop offset bits */ if (n >= max_n) return value; /* all bits requested */ const unsigned mask = (1u << n) - 1; /* n '1's */ return value & mask; } 

Por ejemplo, para obtener 3 bits desde 2273 ( 0b100011100001 ) comenzando en el 5 bit, llame a getbits(2273, 5, 3) , extrae 7 ( 0b111 ).

Por ejemplo, digamos que quiero los primeros 17 bits del valor de 32 bits; ¿Qué es lo que debo hacer?

 unsigned first_bits = value & ((1u << 17) - 1); // & 0x1ffff 

Suponiendo que CHAR_BIT * sizeof(unsigned) es 32 en su sistema.

Supongo que debo usar el operador de módulo y lo probé y pude obtener los últimos 8 bits y los últimos 16 bits

 unsigned last8bitsvalue = value & ((1u << 8) - 1); // & 0xff unsigned last16bitsvalue = value & ((1u << 16) - 1); // & 0xffff 

Si el desplazamiento siempre es cero como en todos los ejemplos de la pregunta, entonces no necesita los getbits() más generales. Hay una instrucción de cpu especial BLSMSK que ayuda a calcular la máscara ((1 << n) - 1) .

Esta es una variación más breve de la respuesta aceptada: la siguiente función extrae los bits de-a inclusivos mediante la creación de una máscara de bits. Después de aplicar una lógica AND sobre el número original, el resultado se desplaza para que la función devuelva solo los bits extraídos. Se han omitido las comprobaciones de índice / integridad para mayor claridad.

 uint16_t extractInt(uint16_t orig16BitWord, unsigned from, unsigned to) { unsigned mask = ( (1<<(to-from+1))-1) << from; return (orig16BitWord & mask) >> from; } 
 #define GENERAL__GET_BITS_FROM_U8(source,lsb,msb) \ ((uint8_t)((source) & \ ((uint8_t)(((uint8_t)(0xFF >> ((uint8_t)(7-((uint8_t)(msb) & 7))))) & \ ((uint8_t)(0xFF << ((uint8_t)(lsb) & 7))))))) #define GENERAL__GET_BITS_FROM_U16(source,lsb,msb) \ ((uint16_t)((source) & \ ((uint16_t)(((uint16_t)(0xFFFF >> ((uint8_t)(15-((uint8_t)(msb) & 15))))) & \ ((uint16_t)(0xFFFF << ((uint8_t)(lsb) & 15))))))) #define GENERAL__GET_BITS_FROM_U32(source,lsb,msb) \ ((uint32_t)((source) & \ ((uint32_t)(((uint32_t)(0xFFFFFFFF >> ((uint8_t)(31-((uint8_t)(msb) & 31))))) & \ ((uint32_t)(0xFFFFFFFF << ((uint8_t)(lsb) & 31)))))))