![]() |
![]() |
![]() |
Vimos num capítulo anterior como os apontadores nos podem permitir operar sobre a memória, a baixo nível. No entanto o C possui outros operadores que actuam ao nível do byte e do bit. Estes operadores poderão ser muito úteis em certos programas que necessitam de controlar de perto o hardware, como por exemplo na programação de sistema (ao nível do sistema operativo).
A combinação dos apontadores e operadores a nível do bit, faz do C uma linguagem capaz de substituir o assembly nas aplicações que dele necessitavam. Como já se referiu, o sistema operativo UNIX, foi quase totalmente escrito em C.
Os operadores bit a bit do C estão sumarizados na tabela seguinte:
& | AND bit a bit |
| | OR bit a bit |
^ | XOR bit a bit |
~ | NOT (inversão) bit a bit |
<< | deslocamento (shift) para a esquerda |
>> | deslocamento (shift) para a direita |
Uma confusão frequente, que é necessário evitar, é a que existe entre o operador &
(AND bit a bit) e o operador &&
(AND lógico entre duas condições cujo
resultado é um dos dois valores booleanos true ou false). O
mesmo acontece com os operadores |
e ||
.
O operador ~
é um operador unário, i. e.,
opera apenas sobre um operando que terá de ser colocado à sua direita.
Os operadores de shift executam o deslocamento do operando colocado à sua
esquerda, um número de posições indicado pelo operando da direita. Este último
operando terá obrigatoriamente de ser um inteiro positivo. No deslocamento para a
esquerda (<<
) as posições que ficam
livres são ocupadas com bits em 0. No deslocamento para a direita (>>
) as posições livres são ocupadas com bits
em 0, se a quantidade deslocada for sem sinal (unsigned), ou com bits idênticos
ao mais significativo, se as quantidades deslocadas possuirem sinal (signed).
Por exemplo, x << 2
,
desloca a representação binária do valor contido em x
,
duas posições (bits) para a esquerda.
Se x
contiver o valor binário 00000010 (2 em
decimal) então: x << 2
faz
com que x
passe a conter o valor 00001000 (8 em
decimal), e x >> 2
faz com que x
passe a conter o valor 00000000 (0 em decimal).
Assim, cada posição deslocada para a esquerda corresponde a uma multiplicação por 2, e cada posição deslocada para a direita corresponde a uma divisão por 2. Geralmente as operações de shift são bastante mais rápidas que as correspondentes operações de multiplicação e divisão.
Para ilustrar alguns destes operadores apresenta-se a seguinte função, capaz de contar o número de bits em 1 contidos num valor de 8 bits (unsigned char), passado como argumento à função:
int bitcount(unsigned char x)
{
int count;
for (count = 0; x != 0; x>>=1)
if (x & 1)
count++;
return count;
}
![]() |
Os campos de bits (bitfields), permitem o empacotamento de vários valores numa palavra de memória (16 ou 32 bits). A aplicação principal é poder trabalhar com valores distintos empacotados num registo de hardware (p. ex. posições de I/O de controlo de alguns periféricos). Poderá servir também para a leitura de ficheiros contendo representações não standard (p. ex. inteiros de 9 bits).
Este empacotamento é feito em C através da declaração de uma estrutura, onde a seguir à definição de cada campo se acrescenta o tamanho, em bits, que o mesmo ocupa numa palavra de memória.
Por exemplo:
struct packed_struct {
unsigned int fl1 : 1;
unsigned int fl2 : 1;
unsigned int fl3 : 1;
unsigned int type : 4;
unsigned int funny_int : 9;
} pack;
Aqui a variável pack
ocupa um total de 16
bits (1 palavra) e contém 5 campos: 3 flags de 1 bit, um campo type
de 4 bits (podendo tomar valores de 0 a 15), e um inteiro não standard de 9
bits (valores de 0 a 511).
O acesso aos vários campos faz-se da forma habitual: o acesso ao campo type
denota-se pack.type
.
Notas:
![]() |
1. Escreva uma função que imprime, em binário, o valor de um unsigned char, passado como argumento.
2. Escreva uma função setbits(x, p, n, y) que retorna o valor de x com os n bits que começam na posição p de x, iguais aos n bits menos significativos de y. Escreva ainda um programa de teste desta função, que pergunte valores ao utilizador, os passe à função e imprima o resultado em binário, juntamente com os valores primitivos de x e y.
3. Escreva um programa que inverta os bits de um valor. O programa deverá imprimir em binário o valor original e o valor invertido.
4. Escreva uma função que rode (rotate) os bits de um determinado valor. Teste a função num programa que imprima o valor original e o valor rodado em binário.
![]() |
2006
Antônio Paulo Neto