2012-09-14 14 views
12

¿Puede alguien explicarme esta función?Cómo crear una máscara con los bits menos significativos configurados en 1 en C

una máscara con los bits menos significativos n pone a 1.

Ex:

n = 6 -> 0x2F, n = 17 -> 0x1FFFF // No entiendo estos términos en todo, especialmente cómo n = 6 -> 0x2F

Además, ¿qué es una máscara?

+3

* también lo que es una máscara * [¿Qué hay de Wikipedia?] (Http://en.wikipedia.org/wiki/Mask_? (informática)) – chris

+1

El 0x2F está equivocado por cierto, debe ser 0x3f – wich

+1

@chris wiki es demasiado confusión ... – sebi

Respuesta

22

La forma habitual es tomar un 1 y cambiarlo a la izquierda n bits. Eso le dará algo como: 00100000. Luego reste uno de eso, lo que borrará el bit establecido, y establecerá todos los bits menos significativos, por lo que en este caso obtendríamos: 00011111.

Una máscara se utiliza normalmente con operaciones bit a bit, especialmente and. Utilizarías la máscara de arriba para obtener los 5 bits menos significativos por sí mismos, aislados de cualquier otra cosa que pudiera estar presente. Esto es especialmente común cuando se trata de hardware que a menudo tendrá un solo registro de hardware que contiene bits que representan un número de cantidades y/o indicadores totalmente independientes y no relacionados.

+2

Tenga en cuenta que ir '1 << w - 1', donde' w' es el ancho de el tipo de datos, para establecer todos menos uno de los bits, es UB. – chris

+0

Exactamente. Echele la culpa a Intel, pero llegó al estándar. – wildplasser

+0

Para obtener una forma de recuperación uniforme del UB en este método, consulte mi respuesta a continuación. – user13972

0

Creo que su primer ejemplo debería ser 0x3f.

0x3f es notación hexadecimal para el número 63 que es 111111 en binario, de modo que los últimos 6 bits (los significativos 6 bits menos) se establecen en 1.

El siguiente programa de C poco será calcular la máscara correcta:

#include <stdarg.h> 
#include <stdio.h> 

int mask_for_n_bits(int n) 
{ 
    int mask = 0; 

    for (int i = 0; i < n; ++i) 
     mask |= 1 << i; 

    return mask; 
} 

int main (int argc, char const *argv[]) 
{ 
    printf("6: 0x%x\n17: 0x%x\n", mask_for_n_bits(6), mask_for_n_bits(17)); 
    return 0; 
} 
0

0x2F es 0010 1111 en binario - esto debe ser 0x3f, que es 0011 1111 en binario y que tiene los 6 bits menos significativos establecidos.

De forma similar, 0x1FFFF es 0001 1111 1111 1111 1111 en binario, que tiene los 17 bits menos significativos establecidos.

una "máscara" es un valor que está destinado a ser combinado con otro valor utilizando un operador de bit a bit como &, | o ^ para establecer individualmente, unset, dar la vuelta o dejar sin cambios los bits en este otro valor.

Por ejemplo, si se combina con la máscara 0x2F algún valor n usando el operador &, el resultado tendrá ceros en todos menos los 6 bits menos significativos, y los 6 bits será copiado sin cambios desde el valor n.

En el caso de una máscara de &, un binario 0 en la máscara significa "incondicionalmente establece el bit de resultado a 0" y un 1 significa "establece el bit de resultado con el valor de bits de entrada". Para una máscara de |, un 0 en la máscara establece el bit resultado que el bit de entrada y una 1 incondicionalmente establece el bit resultado a 1, y por una máscara de ^, una 0 establece el bit resultado que el bit de entrada y una 1 establece el bit de resultado al complemento del bit de entrada.

+0

Ops. Obtuve la edición incorrecta después de su actualización, pero la revertí. ¡Lo siento! – jweyrich

5

Una máscara es un término común para un valor entero que se basa en bits AND, ORed, XORed, etc. con otro valor entero.

Por ejemplo, si desea extraer los 8 dígitos menos significativos de una variable int, haga variable & 0xFF. 0xFF es una máscara.

Del mismo modo, si desea establecer los bits 0 y 8, haga variable | 0x101, donde 0x101 es una máscara.

O si desea invertir los mismos bits, lo hace variable^0x101, donde 0x101 es una máscara.

Para generar una máscara para su caso, debe aprovechar el simple hecho matemático de que si agrega 1 a su máscara (la máscara tiene todos sus bits menos significativos configurados en 1 y el resto en 0), obtiene un valor que es una potencia de 2.

Por lo tanto, si genera la potencia más cercana a 2, puede restar 1 de ella para obtener la máscara.

poderes positivos de la 2 se generan fácilmente con la izquierda operador de desplazamiento << en C.

Por lo tanto, 1 << n rendimientos 2 n. En binario es 10 ... 0 con n 0s.

(1 << n) - 1 producirá una máscara con n bits más bajos fijados a 1.

Ahora, es necesario tener cuidado con los desbordamientos en desplazamientos a la izquierda. En C (y en C++) legalmente no se puede desplazar una variable a la izquierda en tantas posiciones de bits como la variable, por lo que si las entradas son de 32 bits, 1<<32 da como resultado undefined behavior. Los desbordamientos de enteros firmados también deben evitarse, por lo que debe usar valores sin signo, p. 1u << 31.

7

Para la corrección y el rendimiento, la mejor manera de lograr esto ha cambiado desde que se formuló esta pregunta en 2012 debido a la llegada de las instrucciones de IMC en los procesadores modernos x86, específicamente BLSMSK.

He aquí una buena forma de abordar este problema, manteniendo la compatibilidad con versiones anteriores de procesadores anteriores.

Este método es correcto, mientras que las respuestas superiores actuales producen un comportamiento indefinido en casos extremos.

Clang y GCC, cuando se les permite optimizar usando instrucciones BMI, condensarán gen_mask() en solo dos operaciones. Con soporte de hardware, asegúrese de añadir opciones del compilador para obtener instrucciones de IMC: -mbmi -mbmi2

#include <inttypes.h> 
#include <stdio.h> 

uint64_t gen_mask(const uint_fast8_t msb) { 
    const uint64_t src = (uint64_t)1 << msb; 
    return (src - 1)^src; 
} 

int main() { 
    uint_fast8_t msb; 
    for (msb = 0; msb < 64; ++msb) { 
    printf("%016" PRIx64 "\n", gen_mask(msb)); 
    } 
    return 0; 
} 
+0

Tiene un error de uno por uno, AFAICT. –

+1

Lo siento, es un malentendido: habría utilizado el ancho como parámetro (como el N que mencionó el OP), pero como usas el índice del MSB, en realidad es consistente. –

+0

¿Qué hace la consting en este caso? –

Cuestiones relacionadas