2009-02-07 14 views

Respuesta

129

En C, si desea ocultar la manipulación de bits, puede escribir una macro:

#define CHECK_BIT(var,pos) ((var) & (1<<(pos))) 

y usarlo de esta manera:

CHECK_BIT(temp, 3) 

En C++, puede utilizar std::bitset.

+3

En caso de que necesite un valor de verdad simple, debe ser !! ((var) & (1 << (pos))). –

+8

@Eduard: en C, todo '! = 0' es verdadero, entonces ¿para qué molestarse? '1' es exactamente tan verdadero como' 0.1415'! – Christoph

+1

Y en caso de que esté usando C++, podría (debería) escribir una plantilla en lugar de una macro. :) – jalf

66

Comprobar si el bit N (empezando desde 0) se establece:

temp & (1 << N) 

No hay ninguna función interna para esto.

+9

+1 por mencionar que está comenzando desde 0 ya que sospecho que OP pensó que estaba basado en 1 y la respuesta aceptada lo meterá en problemas. :) –

+0

Hm. ¿Por qué esto comienza desde 0? ¿Qué obtenemos cuando '1 << 0'? Lo siento, confundido. – Danijel

+2

OK, lo tengo. Comenzamos desde la 0ª posición, que es '1 << 0', que es 1 sin ningún cambio (cambio 0), que es' 1 << 0 == 1' – Danijel

2

Se puede "simular" el cambio y el enmascaramiento: if ((0x5E/(2 * 2 * 2))% 2) ...

+0

Podríamos ordenar una lista barajando aleatoriamente y probando para ver si ahora está "ordenada". E.g .: while (/ * NOT * /! IsSorted()) {RandomlyShuffle(); } Pero nosotros no ... –

+0

Esta solución es extremadamente derrochadora de recursos y poco intuitiva. divs, muls y mods son las tres funciones más caras. mediante pruebas de comparación, ands y los cambios se encuentran entre los más baratos, algunos de los pocos que realmente se pueden hacer en menos de 5 ciclos. – jheriko

+0

Eso podría ser (y no lo es, porque los procesadores modernos detestan bits y saltos). El OP originalmente preguntó _explicitly_ por una solución "sin cambio de bits y enmascaramiento". Continúa y da más puntos negativos para una respuesta lenta pero igualada. No borraré la publicación solo porque el OP cambió de opinión. – Leonidas

5

Hay, a saber, la instrucción intrínseca _bittest.

+2

El enlace indica "Microsoft específico". Úselo solo si no necesita que su código sea portátil. – mouviciel

+0

Aprendí algo nuevo hoy, ¡gracias! – SAMills

+0

El enlace indica "Específico de Microsoft", pero es una intrínseca tomada del compilador Intel C++, y da como resultado una instrucción BT, por lo que puede hacerlo también con el ensamblador en línea. Por supuesto, eso no lo hace más portátil. –

9

Según this description of bit-fields, hay un método para definir y acceder directamente a los campos. El ejemplo de esta entrada va:

struct preferences { 
    unsigned int likes_ice_cream : 1; 
    unsigned int plays_golf : 1; 
    unsigned int watches_tv : 1; 
    unsigned int reads_books : 1; 
}; 

struct preferences fred; 

fred.likes_ice_cream = 1; 
fred.plays_golf = 1; 
fred.watches_tv = 1; 
fred.reads_books = 0; 

if (fred.likes_ice_cream == 1) 
    /* ... */ 

Además, hay una advertencia de que hay:

Sin embargo, los miembros de bits en estructuras tienen inconvenientes prácticos. En primer lugar, el orden de los bits en la memoria depende de la arquitectura y las reglas de relleno de memoria varían de compilador a compilador. Además, muchos compiladores populares generan código ineficiente para leer y escribir miembros de bit, y hay problemas de seguridad de subproceso potencialmente graves relacionados con campos de bit (especialmente en sistemas multiprocesador) debido al hecho de que la mayoría de las máquinas no pueden manipular conjuntos arbitrarios de bits en la memoria. pero en su lugar debe cargar y almacenar palabras completas.

0

si lo que desea es una forma real codificado:

#define IS_BIT3_SET(var) (((var) & 0x04) == 0x04) 

nota esta HW dependiente y asume este orden de bitsy var es de 8 bits.

#include "stdafx.h" 
#define IS_BIT3_SET(var) (((var) & 0x04) == 0x04) 
int _tmain(int argc, _TCHAR* argv[]) 
{ 
    int temp =0x5E; 
    printf(" %d \n", IS_BIT3_SET(temp)); 
    temp = 0x00; 
    printf(" %d \n", IS_BIT3_SET(temp)); 
    temp = 0x04; 
    printf(" %d \n", IS_BIT3_SET(temp)); 
    temp = 0xfb; 
    printf(" %d \n", IS_BIT3_SET(temp)); 
    scanf("waitng %d",&temp); 

    return 0; 
} 

Resultados: en

+1

La operación & se realiza en valores que no están en la representación interna. –

+0

Hola Remo.D: ¿No estoy seguro de que entiendo tu comentario? He incluido un código 'c' que funciona bien. – simon

+0

Su punto es que no depende del hardware - IS_BIT3_SET siempre probará el 4to bit menos significativo – Eclipse

10

Sí, yo sé que no "tener" a hacerlo de esta manera. Pero generalmente escribo:

/* Return type (8/16/32/64 int size) is specified by argument size. */ 
template<class TYPE> inline TYPE BIT(const TYPE & x) 
{ return TYPE(1) << x; } 

template<class TYPE> inline bool IsBitSet(const TYPE & x, const TYPE & y) 
{ return 0 != (x & y); } 

E.g.:

IsBitSet(foo, BIT(3) | BIT(6)); // Checks if Bit 3 OR 6 is set. 

Entre otras cosas, este enfoque:

  • Tiene capacidad para 8/16/32/64 bits enteros.
  • Detecta llamadas IsBitSet (int32, int64) sin mi conocimiento & consentimiento.
  • Plantilla en línea, por lo que no funciona la llamada de sobrecarga.
  • const & referencias, así que nada necesidades a ser duplicadas/copiado. Y tenemos la garantía de que el compilador recogerá cualquier error tipográfico que intente cambiar los argumentos.
  • 0! = hace que el código sea más claro & obvio. El punto principal para escribir código es siempre comunicarse de forma clara y eficiente con otros programadores, incluidos los de menor nivel.
  • Si bien no se aplica a este caso particular ... En general, las funciones de plantilla evitan el problema de evaluar argumentos varias veces. Un problema conocido con algunas macros #define.
    Ej .: #define ABS (X) (((X) < 0)? - (X): (X))
          ABS (i ++);
21

Solo usaría un std :: bitset si es C++. Sencillo. Sencillo. No hay posibilidad de errores estúpidos.

typedef std::bitset<sizeof(int)> IntBits; 
bool is_set = IntBits(value).test(position); 

o cómo sobre esta tontería

template<unsigned int Exp> 
struct pow_2 { 
    static const unsigned int value = 2 * pow_2<Exp-1>::value; 
}; 

template<> 
struct pow_2<0> { 
    static const unsigned int value = 1; 
}; 

template<unsigned int Pos> 
bool is_bit_set(unsigned int value) 
{ 
    return (value & pow_2<Pos>::value) != 0; 
} 

bool result = is_bit_set<2>(value); 
+2

upvote para el enfoque de metaprogramación de plantillas :) –

+4

@ user21714 Supongo que se refería a std :: bitset <8 * sizeof (int)> – iNFINITEi

+0

o std :: numeric_limits :: digits –

3

uso std :: bitset

#include <bitset> 
#include <iostream> 

int main() 
{ 
    int temp = 0x5E; 
    std::bitset<sizeof(int)*CHAR_BITS> bits(temp); 

    // 0 -> bit 1 
    // 2 -> bit 3 
    std::cout << bits[2] << std::endl; 
} 
+1

Un par de cosas que vale la pena mencionar aquí - bits [3] le dará el cuarto bit - contando desde el LSB a MSB. Para decirlo sin apretar, le dará el 4to bit que cuenta de derecha a izquierda. Además, sizeof (int) da la cantidad de caracteres en un int, por lo que necesitaría ser std :: bitset bits (temp) y bits [sizeof (int) * CHAR_BITS - 3] para probar el conteo de 3er bit de MSB a LSB, que es probablemente la intención. –

+2

Sí, pero creo que el interlocutor (y las personas que provienen de las búsquedas de Google) podrían no tener esa habilidad, y su respuesta podría confundirlos. –

+0

Esta respuesta es terrible. Debe ser eliminado. –

2

Para la solución específica x86 de bajo nivel utilizar el código de operación x86 TEST.

su compilador debe girar _bittest en esto, sin embargo ...

+0

Preferiría [BT] (http://www.posix.nl/linuxassembly/nasmdochtml/nasmdoca.html#section-A.12) sobre TEST ya que BT encaja la tarea de una mejor manera. –

-1

la manera más rápida parece que hay una tabla de consulta para máscaras

3

yo estaba tratando de leer un entero de 32 bits que define las banderas para una objeto en archivos PDF y esto no estaba funcionando para mí

lo fijo que estaba cambiando la definición:

#define CHECK_BIT(var,pos) ((var & (1 << pos)) == (1 << pos)) 

el operando & devuelve un número entero con los indicadores que ambos tienen en 1, y que no se incluyó correctamente en booleano, esto hizo el truco

+0

'! = 0' harían lo mismo. No sé cómo podrían diferir las instrucciones generadas en la máquina. –

0

Si bien es bastante tarde para responder ahora, hay una manera simple que uno podría encontrar si enésimo el bit está configurado o no, simplemente usando los operadores matemáticos POWER y MODULUS.

Digamos que queremos saber si 'temp' tiene enésimo bit configurado o no. La siguiente expresión booleana dará verdadero si el bit está configurado, 0 en caso contrario.

  • (temp MÓDULO 2^N + 1> = 2^N)

Consideremos el siguiente ejemplo:

  • int temp = 0x5E; // en binario 0b1011110 // bit 0 es el LSB

Si yo quiero saber si se ha establecido 3ª poco o no, me sale

  • (94 MÓDULO 16) = 14> 2^3

Entonces la expresión devuelve verdadero, indicando que se ha configurado el tercer bit.

1

¿Por qué no utilizar algo tan simple como esto?

uint8_t status = 255; 
cout << "binary: "; 

for (int i=((sizeof(status)*8)-1); i>-1; i--) 
{ 
    if ((status & (1 << i))) 
    { 
    cout << "1"; 
    } 
    else 
    { 
    cout << "0"; 
    } 
} 

SALIDA: binario: 11111111

+0

si no se puede hacer fácilmente con un ternario: 'std :: cout << (((status & (1 << i))? '' 1 ':' 0 ');'. Debería usar la constante 'CHAR_BIT' de '' en lugar de 8 bits de codificación dura, aunque en este caso usted sabe que el resultado será 8 de todos modos ya que está usando un 'uint8_t' –

6

Lo que la respuesta seleccionada está haciendo realmente mal. La función siguiente devolverá la posición del bit o 0 dependiendo de si el bit está realmente habilitado. Esto no es lo que el cartel estaba pidiendo.

#define CHECK_BIT(var,pos) ((var) & (1<<(pos))) 

Esto es lo que el póster estaba buscando originalmente. La función siguiente devolverá un 1 o 0 si el bit está habilitado y no la posición.

#define CHECK_BIT(var,pos) (((var)>>(pos)) & 1) 
0

Un enfoque va a controlar dentro de la siguiente condición:

if ((mask >> bit) & 1) 

Un programa de explicación será:

#include <stdio.h> 

unsigned int bitCheck(unsigned int mask, int pin); 

int main(void){ 
    unsigned int mask = 6; // 6 = 0110 
    int pin0 = 0; 
    int pin1 = 1; 
    int pin2 = 2; 
    int pin3 = 3; 
    unsigned int bit0= bitCheck(mask, pin0); 
    unsigned int bit1= bitCheck(mask, pin1); 
    unsigned int bit2= bitCheck(mask, pin2); 
    unsigned int bit3= bitCheck(mask, pin3); 

    printf("Mask = %d ==>> 0110\n", mask); 

    if (bit0 == 1){ 
     printf("Pin %d is Set\n", pin0); 
    }else{ 
     printf("Pin %d is not Set\n", pin0); 
    } 

    if (bit1 == 1){ 
     printf("Pin %d is Set\n", pin1); 
    }else{ 
     printf("Pin %d is not Set\n", pin1); 
    } 

    if (bit2 == 1){ 
     printf("Pin %d is Set\n", pin2); 
    }else{ 
     printf("Pin %d is not Set\n", pin2); 
    } 

    if (bit3 == 1){ 
     printf("Pin %d is Set\n", pin3); 
    }else{ 
     printf("Pin %d is not Set\n", pin3); 
    } 
} 

unsigned int bitCheck(unsigned int mask, int bit){ 
    if ((mask >> bit) & 1){ 
     return 1; 
    }else{ 
     return 0; 
    } 
} 

Salida:

Mask = 6 ==>> 0110 
Pin 0 is not Set 
Pin 1 is Set 
Pin 2 is Set 
Pin 3 is not Set 
Cuestiones relacionadas