Bitwise. Escovar Bits

Oi, tudo bem? Depois de um tempo parado com as postagens do blog, hoje vou mostrar como trabalhar com operadores de bits em C. Essa técnica é conhecida como bitwise (e também como “escovar bits”), trata-se basicamente de usar alguns operadores para alterar a sequência de bits de uma variável.

Em C, cada variável têm um tipo, e cada um desses tipos têm um tamanho diferente( quantidade de bits ). Por exemplo, uma variável do tipo char têm o tamanho de 8 bits ( o que equivale a 1 byte ) e uma variável do tipo int geralmente têm 32 bits ( 4 bytes ).

Os principais operadores bitwise são:

  • Operador & ( and )
  • Operador | ( or )
  • Operador ^ ( xor )
  • Operador ~ ( not )
  • Operador >> ( right shift )
  • Operador << ( left shift )

Esses operadores funcionam da seguinte maneira:

& (and)

O operador & compara os bits de cada variável um por um, quando os dois bits (um da variável ‘a’ e outro da variável ‘b’) são iguais a 1 (bit ligado) o retorno é 1, caso contrário o retorno é 0.



char a = 1; // 0000 0001
char b = 5; // 0000 0101

char c = a & b; // 0000 0001

| (or)

O operador | também compara os bits de cada variável um por um, quando pelo menos um dos bits é igual a 1 o retorno é 1, caso contrário o retorno é 0.



char a = 1; // 0000 0001
char b = 5; // 0000 0101

char c = a | b; // 0000 0101

^ (xor)

O operador ^ compara os bits de forma que se os 2 bits( um da variável ‘a’ e outro da variável ‘b’ ) forem iguais ele retorna 0, caso contrario ele retorna 1.



char a = 1; // 0000 0001
char b = 5; // 0000 0101

char c = a ^ b; // 0000 0100

~ (not)

O operador ~ inverte os bits de uma variável, onde era 1 fica 0 e onde era 0 fica 1.



char a = 1; // 0000 0001

char b = ~a; // 1111 1110

<< (left shift) e >> (right shift)

Os operadores << e >> fazem o deslocamentos dos bits para direita e para a esquerda. Preenchendo o restante com 0.



char a = 1; // 0000 0001
char b = a << 2; // 0000 0100

char c = b >> 2; // 0000 0001

Nesses exemplos, utilizei os valores em base 10, mas em C, também é possível especificar valores em binario e hexadecimal. Para isso basta usar a seguinte sintaxe:



char a = 0b101; // binario
char b = 0xff; // hexa

Para tentar apresentar melhor esses operadores vou usar como exemplo um controle de quartos de um hotel. Nesse controle só é necessário saber se o quarto está livre ou se está ocupado. O hotel vai ter 8 quartos e vou armazenar as informações em uma única variável do tipo char, ou seja, cada bit vai representar um quarto. Esse não é um exemplo realista, mas com ele é possível ter uma idéia de como trabalhar com operadores de bits.

O programa inicia assim:



int main(int argc, char **argv)
{
char hotel;

hotel = 0b101; //temos 2 quartos ocupados ( 0000 0101 )

return 0;
}

O primeiro passo é desenvolver uma função para verificar se um determinado quarto está ocupado:



// o quarto é um valor entre 0 e 7 inclusive,
// seria importante testar esse valor
int estaOcupado( char hotel, int quarto )
{
char teste = 1; // 0000 0001

// rotaciona para que o bit ligado fique no quarto desejado
teste = teste << quarto;

// se o retorno for diferente de 0 o quarto esta ocupado
return hotel & teste;
}

int main(int argc, char **argv)
{
char hotel;

hotel = 0b101;

if( estaOcupado( hotel, 0 ) )
printf(" O quarto 0 esta ocupado n" );

return 0;
}

Agora vou desenvolver uma função para ocupar um quarto



void ocuparQuarto( char* hotel, int quarto )
{
char teste = 1; // 0000 0001

teste = teste << quarto;

// o bit ligado do teste garante que o quarto vai ficar ocupado,
// os outros bits do teste estão desligados e não vão alterar o hotel
*hotel = *hotel | teste;
}

int estaOcupado( char hotel, int quarto )
{
char teste = 1; // 0000 0001

teste = teste << quarto;

return hotel & teste;
}

int main(int argc, char **argv)
{
char hotel;

hotel = 0b101;

if( estaOcupado( hotel, 1 ) )
printf(" O quarto 1 esta ocupado n" );
else
printf(" O quarto 1 nao esta ocupado n" );

ocuparQuarto( &hotel, 1 );

if( estaOcupado( hotel, 1 ) )
printf(" O quarto 1 esta ocupado n" );
else
printf(" O quarto 1 nao esta ocupado n" );

return 0;
}

Por último tenho uma função para liberar um quarto:



void liberarQuarto( char* hotel, int quarto )
{
char teste = 1; // 0000 0001

teste = teste << quarto;

// inverte o teste, 0000 0001 fica 1111 1110
teste = ~teste;

// o bit desligado do teste garante que o quarto vai ser liberado,
// os bits ligados do teste não alteram o hotel.
*hotel = *hotel & teste;
}

void ocuparQuarto( char* hotel, int quarto )
{
char teste = 1; // 0000 0001

teste = teste << quarto;

*hotel = *hotel | teste;
}

int estaOcupado( char hotel, int quarto )
{
char teste = 1; // 0000 0001

teste = teste << quarto;

return hotel & teste;
}

int main(int argc, char **argv)
{
char hotel;

hotel = 0b101;

if( estaOcupado( hotel, 1 ) )
printf(" O quarto 1 esta ocupado n" );
else
printf(" O quarto 1 nao esta ocupado n" );

ocuparQuarto( &hotel, 1 );

if( estaOcupado( hotel, 1 ) )
printf(" O quarto 1 esta ocupado n" );
else
printf(" O quarto 1 nao esta ocupado n" );

liberarQuarto( &hotel, 1 );

if( estaOcupado( hotel, 1 ) )
printf(" O quarto 1 esta ocupado n" );
else
printf(" O quarto 1 nao esta ocupado n" );

return 0;
}

Bom pessoal é isso, sei que o exemplo não é muito real, mas vou deixar alguns links para quem quiser saber mais sobre a arte de escovar bits. Até a próxima postagem 🙂

http://www.diogomatheus.com.br/blog/php/operadores-bitwise-bit-a-bit/
http://samuca.wordpress.com/2007/03/26/operadores-bitwise/
http://blog.bsoares.com.br/aspnet/operacoes-binarias

2 respostas para “Bitwise. Escovar Bits”

  1. Parabéns pelo Artigo.
    Não conhecia ainda, só havia ouvido falar e realmente é uma técnica muito boa e necessárias em algumas situações, principalmente para quem trabalhe com softwares embarcados onde se ligam e desligam recursos.
    Muito bem explicado, fácil de entender!
    Continue assim, não nos deixe sem material. hehe

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *