Me gustaría tener una función o (preferiblemente) una macro que calcule la cantidad de turnos necesarios para obtener una determinada máscara de bits.
Actualmente hago algo como:
#define CURRBITMASK 0x30 #define CURRBITSHIFT 4
Lo que quiero hacer:
#define BITMASK1 0x10 #define BITSHIFT1 GETSHIFT(BITMASK1) // 4 ; 0x10 = (0x1 << 4) #define BITMASK2 0x18 #define BITSHIFT2 GETSHIFT(BITMASK2) // 3 ; 0x18 = (0x3 << 3) #define BITMASK3 0xC0 #define BITSHIFT3 GETSHIFT(BITMASK3) // 6 ; 0xC0 = (0x3 << 6) #define BITMASK4 0x40 #define BITSHIFT4 GETSHIFT(BITMASK3) // 6 ; 0x40 = (0x1 << 6)
¿Hay alguna forma de obtener el cambio requerido de la máscara usando solo una macro? Si no, ¿hay una forma más óptima de hacerlo como una función que esta?:
int get_shift(int bitmask) { int count = 0; while (bitmask & 0x1) { bitmask >>= 1; count++; } return count; }
Su implementación es equivalente a contar la cantidad de ceros finales en un número.
Hay varias maneras de hacer esto descritas aquí . Uno de los ejemplos hace esto en siete pasos para un número de 32 bits:
unsigned int v; // 32-bit word input to count zero bits on right unsigned int c = 32; // c will be the number of zero bits on the right v &= -signed(v); if (v) c--; if (v & 0x0000FFFF) c -= 16; if (v & 0x00FF00FF) c -= 8; if (v & 0x0F0F0F0F) c -= 4; if (v & 0x33333333) c -= 2; if (v & 0x55555555) c -= 1;
Esta respuesta a una pregunta mía da una solución macro:
/* Number of bits in inttype_MAX, or in any (1<<b)-1 where 0 <= b < 3E+10 */ #define IMAX_BITS(m) ((m) /((m)%0x3fffffffL+1) /0x3fffffffL %0x3fffffffL *30 \ + (m)%0x3fffffffL /((m)%31+1)/31%31*5 + 4-12/((m)%31+3))
o si quiere más simple y no le importan los números enteros> 2040 bits:
/* Number of bits in inttype_MAX, or in any (1<<k)-1 where 0 <= k < 2040 */ #define IMAX_BITS(m) ((m)/((m)%255+1) / 255%255*8 + 7-86/((m)%255+12))
Para su uso, la m
que desea pasar es (x&-x)-1
. x&-x
quita todo menos el bit más bajo de x
, lo que produce una potencia de dos, y luego restando 1 lo pone en la forma correcta para estas macros.
La respuesta vinculada vincula a una publicación de Usenet sobre cómo funciona.
He creado una solución rápida que no necesita pasos iterativos. Sin embargo, nunca se sabe la cantidad de bits a desplazar, sino la enésima potencia del desplazamiento. Luego, el cambio se realiza a través de la multiplicación/división, que el compilador optimizará como cambios de bits.
#define BITS2SHIFT(mask) (mask&-mask) #define MOV2MASK(val,mask) (val*BITS2SHIFT(mask))&mask #define MASK2VAL(val,mask) (val&mask)/BITS2SHIFT(mask)
Vea este ejemplo sobre cómo usarlo.