 |
Operações com bits na linguagem C
MC404 2o semestre de 2015 |
 |
Atualizado em 17/08/2015
Prof. Célio
A linguagem C foi criada em 1972 pelos desenvolvedores do sistema Unix (Ken Thompson e Dennis Ritchie)
com o objetivo de nela escreverem o sistema operacional Unix (Linux é uma versão moderna do Unix e Ubuntu
é uma distribuição popular).
Num sistema operacional operações de Entrada/Saída usam extensivamente manipulação de bits, por isto C dispõe
de um conjunto compreensivo de operadores lógicos binários para este fim. Quando o segundo operando de uma operação
lógica binária é uma constante ele é comumente chamado de "máscara". No que se segue suporemos que "variavel" foi declarada
como "unsigned int": nesse caso o gcc usa 32 bits para armazenar a variavel.
- "or" | - faz o "ou" bit a bit dos operandos. Exemplo: variavel = variavel | 0x0f;
- "and" & - faz "and" bit a bit dos operandos. Exemplo: variavel = variavel & 0xf0;
- "xor" ^ - faz o "ou exclusivo bit a bit dos operandos. Exemplo: variavel = variavel ^ 0xffffffff;
- "deslocamento para a esquerda <<" - desloca á esquerda o 1o operando do número de bits no segundo operando,
inserindo bits 0 nos bits deslocados.
Exemplo: variavel = variavel << 2;I (multiplica variavel por 4)
Obs: (i) a expressão 1 << k gera uma máscara muito conveniente que é:
"desloque a constante 1 k bits à esquerda" (k= 0..31). Exemplo de seu uso:
"ligar o bit 17 de uma palavra" (variável): variavel = variavel | (1 << 17);
(ii) a atribuição: variavel= -1; gera uma máscara com 32 bits iguais a 1 (0xFFFFFFFF).
- "deslocamento para a direita >>" - desloca á direita o 1o operando do número de bits no segundo operando.
Se o primeiro operando for do tipo unsigned int 0s são inseridos nos bits deslocados, mas se for do
tipo int o sinal (bit mais significativo) é copiado nos bits deslocados.
Exemplo: variavel = variavel >> 4; (divide variavel por 16)
Existe também um operador unário "~" que complementa todos os bits do operando;
Observe que: variavel= ~variavel equivale a: variavel= variavel ^ 0xffffffff
Exercícios
Considere variáveis de 32 bits. Note que bits são numerados da direita
para a esquerda de 0 (bit menos "significativo") a 31 (bit "mais significativo").
Faça trechos de programa em C para:
- Ligar/desligar o bit k (constante) de uma variável.
- Inverter os bits de uma variável sem usar o operador ~.
- Fazer o "ou" de uma variável dado um apontador para a mesma, com o valor de outra variável.
- Fazer o "and" de uma variável dado um apontador para a mesma, com o valor de outra variável.
- Multiplicar por 16 uma variável sem usar o operador de multiplicação *.
- Dividir por 16 uma variável sem usar o operador de divisão /.
- Ligar/desligar os n bits menos significativos de uma variável sem alterar os outros bits
(n = constante (0-31)).Dica: a partir da máscara 0xffffffff (-1), gere uma máscara com os
n bits menos sigificativos iguais a 0
- Ligar/desligar os n bits mais significativos de uma variável sem alterar os outros bits (n = constante). Dica: - mesma do problema anterior.
- Considere o campo de bits de uma variável localizado entre os n bits mais significativos e os n bits menos significativos:
(i) desligue os bits desse campo sem alterar os outros bits.
(ii) ligue os bits desse campo sem alterar os outros bits.
Sugestão: use as duas máscaras dos dois problemas anteriores para gerar
a máscara desejada.
Exercícios mais elaborados
Escreva em C as seguintes funções (derivadas de instruções com o mesmo nome nos processadores ARM Cortex M3):
- ubfx(unsigned int * dest,unsigned int src, const int sbit, const int nbits)
( ubfx = unsigned bit field extract),
com o objetivo de extrair da variavel src um campo de nbits a partir do bit sbit menos significativo
(ou seja, incluindo os bits sbit, sbit+1, ...,sbit+nbits-1),
e inseri-lo nos nbits menos significativos da variável dest, zerando os bits restantes da mesma.
- sbfx(int * dest, int src, const int sbit, const int nbits) (signed bit field extract),
semelhante ao anterior, porém o bit mais significativo do campo deve ser considerado como um bit de sinal
e deve ser propagado para os 32-nbits mais significativos de dest.
Dica: é possivel escrever as duas funções acima sem usar máscaras, apenas operações
de deslocamento!
- bfc(unsigned int * dest, const int sbit, const int nbits) (bit field clear):
zerar os bits sbit a sbit+nbits-1 da variável dest, sem alterar os outros bits da variável
Sugestão: crie duas máscaras apropriadas: m1=|1111111|sbits 0| e m2=|000000|nbits + sbits 1|.
O seu uso deve, então, ficar claro.
- bfi(unsigned int * dest, unsigned int src, const int sbit, const int nbits) - bit field insert:
extrair um campo com os nbits menos significativos da variável src e inseri-lo na variavel dest
a partir do bit sbit sem alterar os outros bits de dest
Sugestão: utilize o problema anterior para zerar o campo desejado na variável dest e sem usar
máscaras gere o campo apropriado a partir da variável src; o resto fica óbvio.