C / C ++ verifica se um bit está definido, ou seja, variável int

100
int temp = 0x5E; // in binary 0b1011110.

Existe uma maneira de verificar se o bit 3 em temp é 1 ou 0 sem deslocamento de bit e mascaramento.

Só quero saber se existe alguma função incorporada para isso ou se sou forçado a escrever uma.

Milão
fonte

Respostas:

157

Em C, se você deseja ocultar a manipulação de bits, pode escrever uma macro:

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

e use-o desta forma para verificar o enésimo bit da extremidade direita:

CHECK_BIT(temp, n - 1)

Em C ++, você pode usar std :: bitset .

mouviciel
fonte
3
Caso você precise de um valor de verdade simples, deve ser !! ((var) & (1 << (pos))).
Eduard - Gabriel Munteanu
10
@Eduard: em C, tudo != 0é verdade, então por que se preocupar? 1é exatamente tão verdadeiro quanto 0.1415!
Christoph
1
E caso você esteja usando C ++, você pode (deve) escrever um modelo ao invés de uma macro. :)
jalf
2
Em C, isso é bom. Mas esse tipo de macros em C ++. Isso é horrível e tão sujeito a abusos. Use std :: bitset
Martin York
5
Ugh std::bitset, realmente? Claro, ao invés de fazer um pequeno trabalho (e potencialmente alguns modelos realmente bons) para verificar um único bit, use um contêiner inchado que armazena (na minha implementação) cada 'bit' em um de outra forma não utilizado unsigned long. Que desperdício de espaço!
underscore_d
86

Verifique se o bit N (começando em 0) está definido:

temp & (1 << N)

Não há função embutida para isso.

Joao da silva
fonte
16
+1 por mencionar que está começando de 0, pois suspeito que o OP estava pensando com base em 1 e a resposta aceita o colocará em apuros. :)
Jim Buck
Hm. Por que isso começa em 0? O que ganhamos quando 1 << 0?? Desculpe, confuso.
Danijel
6
OK, entendi. Começamos da 0ª posição, ou seja 1<<0, que é 1 sem qualquer deslocamento (deslocamento 0), que é1<<0 == 1
Danijel
27

Eu usaria apenas um std :: bitset se for C ++. Simples. Direto. Sem chance para erros estúpidos.

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

ou que tal essa bobagem

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);
user21714
fonte
4
@ user21714 Acho que você quis dizer std :: bitset <8 * sizeof (int)>
iNFINITEi
ou std :: numeric_limits <int> :: digits
Léo Lam
@iNFINITEi std::bitset<CHAR_BIT * sizeof(int)>para ser ainda mais correto
Xeverous
13

Sim, eu sei que não "tenho" que fazer desta forma. Mas costumo escrever:

    /* 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); }

Por exemplo:

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

Entre outras coisas, esta abordagem:

  • Acomoda inteiros de 8/16/32/64 bits.
  • Detecta chamadas IsBitSet (int32, int64) sem meu conhecimento e consentimento.
  • Modelo embutido, portanto, nenhuma sobrecarga de chamada de função.
  • referências constantes , então nada precisa ser duplicado / copiado. E temos a garantia de que o compilador pegará qualquer erro de digitação que tente alterar os argumentos.
  • 0! = Torna o código mais claro e óbvio. O ponto principal para escrever código é sempre comunicar-se de forma clara e eficiente com outros programadores, incluindo aqueles de menor habilidade.
  • Embora não seja aplicável a este caso específico ... Em geral, as funções de modelo evitam o problema de avaliar argumentos várias vezes. Um problema conhecido com algumas macros #define.
    Ex: #define ABS (X) (((X) <0)? - (X): (X))
          ABS (i ++);
Mr.Ree
fonte
13

O que a resposta selecionada está fazendo está realmente errado. A função abaixo retornará a posição do bit ou 0 dependendo se o bit está realmente habilitado. Não era isso que o cartaz estava pedindo.

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

Aqui está o que o pôster estava procurando originalmente. A função abaixo retornará 1 ou 0 se o bit estiver habilitado e não a posição.

#define CHECK_BIT(var,pos) (((var)>>(pos)) & 1)
shocker92
fonte
1
Demorou algum tempo até eu entender o que você quis dizer. Mais exato: a primeira função retorna 2 à potência da posição do bit se o bit estiver definido, 0 caso contrário.
lukasl1991
1
Este é exatamente o problema que acabei de encontrar ao usá-lo como bool has_feature = CHECK_BIT(register, 25);bom saber que eu poderia fazer isso sem a dupla negação.
Jimmio92
11

De acordo com esta descrição de campos de bits , existe um método para definir e acessar campos diretamente. O exemplo nesta entrada é:

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)
    /* ... */

Além disso, há um aviso lá:

No entanto, membros de bits em estruturas têm desvantagens práticas. Primeiro, a ordenação dos bits na memória depende da arquitetura e as regras de preenchimento da memória variam de compilador para compilador. Além disso, muitos compiladores populares geram código ineficiente para ler e gravar membros de bits, e há problemas de segurança de thread potencialmente graves relacionados a campos de bits (especialmente em sistemas multiprocessadores) devido ao fato de que a maioria das máquinas não pode manipular conjuntos arbitrários de bits na memória, mas, em vez disso, deve carregar e armazenar palavras inteiras.

gimel
fonte
5

Use 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;
}
Martin York
fonte
1
Algumas coisas que valem a pena mencionar aqui - bits [3] darão a você o quarto bit - contando do LSB ao MSB. Para resumir, ele lhe dará a contagem de 4 bits da direita para a esquerda. Além disso, sizeof (int) fornece o número de caracteres em um int, então ele precisa ser std :: bitset <sizeof (int) * CHAR_BITS> bits (temp) e bits [sizeof (int) * CHAR_BITS - 3] para testar o terceiro bit contando de MSB para LSB, que provavelmente é a intenção.
plástico chris
2
Sim, mas acho que o questionador (e as pessoas que vêm das pesquisas do Google) podem não ter essa habilidade e sua resposta pode enganá-los.
plástico chris
Essa resposta é terrível. Deve ser excluído.
Adam Burry
O valor não tempprecisa ser refletido para torná-lo "big-endian"?
jww
4

Existe, a saber, a instrução intrínseca _bittest .

Dave Van den Eynde
fonte
3
O link indica "Específico da Microsoft". Use-o apenas se você não precisar que seu código seja portátil.
mouviciel
O link indica "Específico da Microsoft", mas é um intrínseco herdado do compilador Intel C ++ e resulta em uma instrução BT, portanto, você também pode fazer isso com o montador embutido. Claro, isso não o torna mais portátil.
Dave Van den Eynde
1
Também é específico para a arquitetura x86. Portanto, não, definitivamente não é portátil.
jalf
Tenho certeza de que outras arquiteturas têm opções semelhantes.
Dave Van den Eynde
O ponto principal dos intrínsecos é que eles tiram proveito do hardware, se ele existir, e usam uma substituição de software se o hardware não for compatível.
Eclipse
4

Eu uso isso:

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

onde "pos" é definido como 2 ^ n (ig 1,2,4,8,16,32 ...)

Retorna: 1 se verdadeiro 0 se falso

Sonho Antrópico
fonte
2
Acho que esta é a única resposta correta para C e C ++. É o único que respeita o requisito "... sem deslocamento de bits e mascaramento" . Você provavelmente deve declarar explicitamente o uso 4 = 2^(3-1)para a posição de bit 3, uma vez que era parte da questão.
jww
3

eu estava tentando ler um inteiro de 32 bits que definia os sinalizadores de um objeto em PDFs e isso não estava funcionando para mim

o que consertou foi mudar a definição:

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

o operando & retorna um inteiro com os sinalizadores que ambos têm em 1, e não estava convertendo corretamente em booleano, isso funcionou

Ismael
fonte
!= 0faria o mesmo. Não sei como as instruções de máquina geradas podem ser diferentes.
Adam Burry
2

Você pode "simular" mudança e mascaramento: if ((0x5e / (2 * 2 * 2))% 2) ...

Leônidas
fonte
Poderíamos classificar uma lista aleatoriamente embaralhando-a e testando para ver se agora está "classificada". Por exemplo: while (/ * NOT * /! IsSorted ()) {RandomlyShuffle (); } Mas nós não ...
Mr.Ree
Esta solução é extremamente desperdiçadora de recursos e pouco intuitiva. divs, muls e mods são as três funções mais caras. por testes de comparação, ands e shifts estão entre os mais baratos - alguns dos poucos que você pode realmente fazer em menos de 5 ciclos.
jheriko
Isso pode ser (e não é, porque os processadores modernos detestam bits e saltos). O OP originalmente pediu explicitamente uma solução "sem deslocamento de bits e mascaramento". Então vá em frente e dê mais pontos negativos para uma resposta correspondente, mas lenta. Não vou deletar a postagem só porque o OP mudou de ideia.
Leonidas
Parece complicado. Não vamos votar esta resposta. Às vezes é bom explorar outros pontos de vista.
Viet
2

Para a solução específica x86 de baixo nível, use o opcode x86 TEST .

Seu compilador deve transformar _bittest nisso ...

jheriko
fonte
Eu preferiria o BT ao invés de TEST, já que o BT se encaixa melhor na tarefa.
u_Ltd.
1

Por que não usar algo tão simples como isso?

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";
  }
}

SAÍDA: binário: 11111111

Zeilja
fonte
se mais pode ser feito facilmente com um ternário: std::cout << (((status & (1 << i)) ? '1' : '0');. Você deve usar a CHAR_BITconstante de em <climits>vez de codificar 8 bits, embora, neste caso, saiba que o resultado será 8 de qualquer maneira, já que está usando umuint8_t
Ryan Haining
0

se você quer apenas uma forma real de código:

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

observe que este depende de hw e assume esta ordem de bits 7654 3210 e var é 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;
}

Resulta em:

1 0 1 0

simon
fonte
1
A operação & é feita em valores que não estão na representação interna.
Remo.D
Olá Remo.D - Não tenho certeza se entendi seu comentário? Eu incluí algum código 'c' que funciona muito bem.
simon
O que ele quer dizer é que não depende do hardware - IS_BIT3_SET sempre testará o quarto bit menos significativo
Eclipse
0

Embora seja muito tarde para responder agora, há uma maneira simples de descobrir se o enésimo bit está definido ou não, simplesmente usando os operadores matemáticos POWER e MODULUS.

Digamos que queremos saber se 'temp' tem o enésimo bit definido ou não. A seguinte expressão booleana fornecerá verdadeiro se o bit for definido, 0 caso contrário.

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

Considere o seguinte exemplo:

  • temp int = 0x5E; // no binário 0b1011110 // BIT 0 é LSB

Se eu quiser saber se o terceiro bit está definido ou não, recebo

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

Portanto, a expressão retorna verdadeiro, indicando que o terceiro bit está definido.

Ouroboros
fonte
0

Uma abordagem será verificar dentro da seguinte condição:

if ( (mask >> bit ) & 1)

Um programa de explicação 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;
   }
}

Resultado:

Mask = 6 ==>>  0110
Pin 0 is not Set
Pin 1 is Set
Pin 2 is Set
Pin 3 is not Set
Michi
fonte
0
#define CHECK_BIT(var,pos) ((var>>pos) & 1)

pos - posição do bit começando de 0.

retorna 0 ou 1.

Artūrs Laizāns
fonte
-1

Eu faço isso:

LATGbits.LATG0 = ((m & 0x8)> 0); // para verificar se o bit-2 de m é 1

mathengineer
fonte
-2

a maneira mais rápida parece ser uma tabela de pesquisa de máscaras

oldUser
fonte