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

2 minutos de lectura

¿Como extraigo bits n especificos de un entero sin signo
hektor

¿Alguien podría 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; que es lo que debo hacer?
Supongo que se supone 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?

  • Tenga en cuenta que su código, tal como está escrito, en realidad extrae los últimos 4 y 5 bits, respectivamente (no 8 y 16, como escribió).

    – Aarón Dufour

    4 de noviembre de 2011 a las 16:20

  • @AaronDufour ¿Puede explicar su comentario? Me interesa porque es eso de 4 y 5 bits

    – Cholti Paul Ttiopic

    12 de junio de 2018 a las 7:11


  • @CholthiPaulTtiopic Puede obtener los últimos n bits de un número x con x % (2 ^ n) (x % 16 -> x % 2^4 -> 4 bits, y de manera similar x % 32 -> 5 bits). Si lo haces x % n entonces encontrará que su salida solo varía de 0 a n-1, mientras que n bits pueden contener números de 0 a 2^n-1.

    – Aarón Dufour

    13 de junio de 2018 a las 0:11

  • ¡Explicación fantástica de @AaronDufour!

    – Cholti Paul Ttiopic

    13 de junio de 2018 a las 5:02

En lugar de pensar en ello como ‘extraer’, me gusta pensar en ello como ‘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, puede usar un truco simple.

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

Si desea aislar una serie de X bits en medio de ‘valor’ a partir de ‘startBit’…

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

Espero que esto ayude.

  • su énfasis en hacer que el byte de Máscara sea primero es realmente útil para resolver tales problemas

    – Pranav Nandan

    8 de marzo de 2016 a las 14:12

  • necesita más explicación parte de enmascaramiento. no obtuve mucho

    – usuario765443

    21 de febrero de 2017 a las 15:54

  • @user765443: suponga que desea extraer los últimos 3 bits de 0101, 1 << 3 = 1000,1000-1=0111,0101 y 0111=101 (últimos 3 bits extraídos). (1<

    – AlphaGoku

    2 de abril de 2018 a las 3:20

  • Este enfoque no funciona si X = 32 para int (o 64 para long)

    – nudo

    13 oct 2020 a las 9:03

  • @knst – Tienes razón; bajo las condiciones a las que hizo referencia, nos encontramos con un comportamiento indefinido cuando cambiamos de bit. Por lo tanto, dependiendo del procesador, podría funcionar (o no); en otras palabras, no es portátil para esos casos. También se puede hacer la observación de que si está tratando de extraer o aislar todos los bits, simplemente acceda a la variable como lo haría normalmente y no se moleste en aplicar máscaras innecesarias.

    – chispeante

    13 oct 2020 a las 18:47

1647584467 719 ¿Como extraigo bits n especificos de un entero sin signo
pnecis

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 desde el bit a hasta el 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 los bits 12 a 16, llame a la función y luego simplemente & (AND lógico) r con tu numero N

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

Si quieres puedes cambiar el resultado. Espero que esto ayude

  • no hay necesidad de perder tiempo buscando una máscara pequeña. sólo((1 << n) - 1) << b

    – phuclv

    29 de agosto de 2013 a las 10:07

  • @pnezis Creo que su función falla con un caso extremo. Si quiero obtener los dos primeros bits, createMask me da el 2do y 3er bit porque serviría 1 << 1seguido por 1 << 2. La máscara de bits devuelta es 110 – que pone a cero el primer bit.

    – Jack

    14 de marzo de 2016 a las 9:32


  • @Jack si quieres los primeros dos bits, entonces tienes que llamar createMask con 0 y 1 como argumentos, para obtener el 0x03 máscara.

    – pnecis

    16 de marzo de 2016 a las 13:09

  • Esto es más rápido y funcionó para mí también con uint64_t‘s: ((1ull << (b - a)) - 1ull) << a

    – Petr Manek

    26 de diciembre de 2016 a las 13:54

Modulus funciona para obtener bits inferiores (solo), aunque creo value & 0x1ffff expresa “tomar los 17 bits inferiores” más directamente que value % 131072por lo que es más fácil de entender haciendo eso.

Los 17 bits superiores de un valor sin signo de 32 bits serían value & 0xffff8000 (si los quiere todavía en sus posiciones en la parte superior), o value >> 15 si desea que los 17 bits superiores del valor estén en los 17 bits inferiores del resultado.

  • Para la segunda parte de su respuesta, tal vez debería haber value >> 15 & 0x1ffff. El desplazamiento a la derecha para números enteros está definido por la implementación; tanto GCC como MSVC lo tienen aritmético, no lógico.

    –Joseph Quinsey

    4 de noviembre de 2011 a las 18:39

  • @Joseph: la pregunta dice que es un número entero sin signo de 32 bits, por lo que el resultado del desplazamiento a la derecha está definido por el estándar. Si estuviera firmado, el efecto del desplazamiento a la derecha en un valor negativo está (como usted dice) completamente definido por la implementación. No es necesario que sea ni aritmético ni lógico, el resultado puede ser cualquier cosa. En la práctica, por supuesto, todos eligen un cambio aritmético para los valores con signo, pero si le preocupa escribir según el estándar, es mejor evitarlo por completo (como lo ha hecho el interrogador).

    –Steve Jessop

    4 de noviembre de 2011 a las 23:46


1647584467 405 ¿Como extraigo bits n especificos de un entero sin signo
jfs

hay un solo BEXTR (Extracción de campo de bits (con registro)) instrucción x86 en CPU Intel y AMD y UBFX en BRAZO. Hay funciones intrínsecas como _bextr_u32() (el enlace requiere inicio de sesión) que permiten invocar esta instrucción explícitamente.

ellos implementan (source >> offset) & ((1 << n) - 1) Código C: obtener n bits continuos de source comenzando en el offset poco. Aquí hay una definición de función completa que maneja casos extremos:

#include <limits.h>

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 pedacitos de 2273 (0b100011100001) a partir de 5-th bit, llamada getbits(2273, 5, 3)—extrae 7 (0b111).

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

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

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

Supongo que se supone 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 es siempre cero como en todos sus ejemplos en la pregunta, entonces no necesita el más general getbits(). Hay una instrucción de CPU especial BLSMSK que ayuda a calcular la máscara ((1 << n) - 1).

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

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

1647584468 915 ¿Como extraigo bits n especificos de un entero sin signo
florindo

Esta es una variación más breve de la respuesta aceptada: la función a continuación extrae los bits de a inclusive creando 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 omitieron 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;
}

A nivel de bits Y su número entero con la máscara que tiene exactamente los bits establecidos que desea extraer. Luego cambie el resultado a 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);

Editar: 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 “dentro” de uno más grande. Puede omitir el desplazamiento a la derecha (>>) si esto no se desea.

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad