Bitwise. Escovar Bits

20 de jan de 2014 - Paulo Dias


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

Paulo Dias

Graduado no curso tecnólogo em análise e desenvolvimento de sistemas. Defensor do Software Livre e da democratização da informação. Possui as certificações Linux LPIC-1 e Java OCA. Atualmente exerce a função de coordenador técnico na área de telecomunicações.

Siga-me no Twitter