Ler bits de um stream em C++

Em muitas situações é necessária a leitura de bits a partir de um stream de dados provenientes de um ficheiro ou de um socket. No entanto, as funções usuais permitem ler, no mínimo, variáveis de tipo caracter as quais têm tamanho igual a um byte (um byte são oito bits). Assim sendo, o problema resume-se a ler os bits individuais de uma variável desse tipo.

Existem duas maneiras de ler bits de uma variável do tipo caracere sem sinal (unsigned char). Uma consiste na utilização de campos de bits e a outra baseia-se na utilização dos operadores bit-a-bit. Apresento, de seguida, uma descrição de ambas.

Campos de bits (bit fields) correspondem a uma estrutura struct cujos campos têm tamanhos em bits especificados. Por exemplo, a maoir parte dos controladores de hardware como é o caso das disk drives contém uma série de registos que podem ser condensados em apenas um inteiro (int) como é exemplificado na figura.

disk_register Este registo pode ser representado pelo bit field:

struct REGISTER{
    unsigned register: 1;
//campo de 1 bit
    unsigned error_occured: 1;
    unsigned disk_spinning: 1;
    unsigned write_protect: 1;
    unsigned head_loaded: 1;
    unsigned error_code: 8;  //campo de 8 bits
    unsigned track: 9; //campo track tem 9 bits
    unsigned sector: 5;
    unsigned command: 5;
};

Neste caso, a leitura deste registo terá de ser feita a partir de um inteiro de 32-bit devido ao número de bits total para este campo (para o unsigned char é semelhante). Suponhamos que temos o registo na posição de memória (tipo int) apontado por

int *memory_register;

Para obter os valores dos campos, converte-se o apontador para o tipo inteiro em apontador para o campo de bits e lê-se cada um dos campos do mesmo modo que uma estrutura normal:

struct REGISTER *reg = (struct REGISTER *) memory_register;  //cast dos apontadores
unsigned int regist = reg->register;
//regist recebe o valor do primeiro bit

O principal inconveniente deste método prende-se com a portabilidade do código entre máquinas e até mesmo entre compiladores. Este facto deve-se ao tamanho dos inteiros, ordem com que os bits são armazenados e limites de memória que um campo de bits pode ter.

O outro método uiliza operadores bit-a-bit. Por exemplo, se tivermos o inteiro 10 com representação binária 1010 onde os restantes bits mais significativos são zero, vemos que

1010 | 0011 = 1011, isto é, 10 | 3 = 11
1010 & 0011 = 0010, isto é, 10 & 3 = 2

Para obter os bits de 10 verificamos que

1010 & 0001 = 0000 ou 10 & 1 = 0
1010 & 0010 = 0010 ou 10 & 2 = 2
1010 & 0100 = 0000 ou 10 & 4 = 0
1010 & 1000 = 1000 ou 10 & 8 = 8

A partir daqui, não é difícil concluir que, sendo n um número inteiro, n & 2p é nulo caso o bit na posição p-1 também o seja e vale 2p caso contrário. O código que se segue permite obter o bit na posição p do inteiro n:

int bit_res = (n & (1 << p-1)) >> p-1;

No artigo O protocolo MIDI apresentei o famigerado protocolo de comunicação electrónica entre instrumetos musicais, onde as mensagens são enviadas em pacotes de 1 byte, isto é, 8 bits. No entanto, cada byte está subdividido em unidades mais pequenas, sendo necessário o respectivo tratamento bit-a-bit. Outras aplicações compreendem a compressão de dados, codecs de audio e vídeo, entre outras.

Sobre Sérgio O. Marques

Licenciado em Física/Matemática Aplicada (Astronomia) pela Faculdade de Ciências da Universidade do Porto e Mestre em Matemática Aplicada pela mesma instituição, desenvolvo trabalho no PTC (Porto Technical Centre) - Yazaki como Administrador de bases-de-dados. Dentro o meu leque de interesses encontram-se todos os temas afins às disciplinas de Matemática, Física e Astronomia. Porém, como entusiasta, interesso-me por temas relacionados com electrónica, poesia, música e fotografia.
Esta entrada foi publicada em Computadores e Internet. ligação permanente.

Deixe uma Resposta

Preencha os seus detalhes abaixo ou clique num ícone para iniciar sessão:

Logótipo da WordPress.com

Está a comentar usando a sua conta WordPress.com Terminar Sessão / Alterar )

Imagem do Twitter

Está a comentar usando a sua conta Twitter Terminar Sessão / Alterar )

Facebook photo

Está a comentar usando a sua conta Facebook Terminar Sessão / Alterar )

Google+ photo

Está a comentar usando a sua conta Google+ Terminar Sessão / Alterar )

Connecting to %s