Go brincando com bits

Como manipular bits usando Golang

Brincando com bits

Estou brincando com um projeto de um interpretador BASIC escrito em Go e a saída de video em modo texto segue o padrão de cores do CGA ou seja um byte contem nos quatro bits mais altos o código para a cor do fundo e nos quatro bits mais baixos o código para a cor da fonte. Ou seja 16 cores para as letras e 16 cores para o fundo. Se o flag de blink estiver ativo o bit mais alto indica que o sistema deve “piscar” a letra. Com isso acontece uma coisa interessante, só as cores de fundo com esse bit ligado podem piscar, por exemplo o azul, cor 0x09 que é binário é 1001 pisca, mas o vermelho 0x4 não pisca porque em binário é 0100.

Essa brincadeira parece complicada mas na verdade é muito simples, precisamos apenas aprender algumas poucas operações para poder manipular bits.

Antes de começarmos vamos combinar o seguinte, quando eu falar sobre a parte superior ou alta de um conjunto de bits estou me referindo aos bits mais a esquerda, e quando estiver falando da parte inferior ou parte baixa estou falando dos bits mais a direita. Nem sempre é assim, mas para efeito desse texto é assim que funciona é o que chamamos de lite-endian

Shift (<< e >>, desloca bits)

Shift é o operador para movre bits para direita << ou esquerda >>

Exemplo:

00000001 << 1 resulta em: 00000010
00000001 << 2 resulta em: 00000100
00000001 << 3 resulta em: 00001000

10000000 << 1 resulta em: 01000000
10000000 << 2 resulta em: 00100000
10000000 << 3 resulta em: 00010000

AND (&)

Usamos end para definir uma mascara e usamos essa mascara para extrair a parte que queremos de um conjunto de bits.

Exemplo:

Digamos que queremos extrair apenas os quatro bits centrais de um byte, para isso definimos a seguinte mascara: 00111100 note que os bits que queremos extrair estão com 1 e os que não queremos estão com 0. Daí basta comparar o byte que contem o valor a ser extraído com a mascara usando AND (&)

 valor	 & mascara
10101010 & 00111100 resulta em: 00101000

O que and faz é comparar cada um dos bits com o seu correspondente na mascara e apenas onde os dois bits forem 1 vai ser 1 no resultado. Com isso os outros bits fora da mascara foram zerados.

E agora podemos usar shift para a direita , andar duas casas e obter o valor que queremos extrair em um byte.

00101000 >> 2 resulta em: 00001010

Ou seja usamos AND junto com uma mascara de bits para separar as partes que queremos de um conjunto de bits.

OR (|)

OR nesse caso é o inverso, usaremos para combinar dois conjuntos de bits em um único.

Exemplo:

Digamos que queremos juntar esses quatro bits 1010 na parte superior de um byte seguido desses 4 bits 0101 na parte inferior.

Primeiro movemos os 4 bits para a parte superior do byte:

00001010 << 4 resulta em: 10100000

Daí usamos OR para juntar a parte superior e a inferior:

10100000 | 00000101 resulta em: 10100101

Vamos ver um exemplo em Go:

package main

import "fmt"

func main() {

	/*
		Pega os códigos da cor da fonte e do fundo
		e combina os dois em um único byte
	*/

	var b, f byte

	b = 0x9 // cor do fundo (azul claro)
	f = 0x4 // cor da fonte (vermelho)

	// combina os dois códigos para compor o código da cor
	c := (f & 0x0f) | (b << 4)

	/*
		Pega o código da cor e separa a cor da fonte
		e do fundo para poder usar separadamente
	*/

	h := (c & 0xf0) >> 4 // High Nibble
	l := c & 0x0f        // Low Nibble
	blink := (c & 0x80) >> 7

	/*
		Mostra os resultados
	*/

	fmt.Printf("cor do fundo.: %04b\n", h)
	fmt.Printf("cor da letra.:     %04b\n", l)
	fmt.Printf("codigo da cor: %08b\n", c)
	fmt.Printf("blink........: %b", blink)
}

Teste no The Go Playground

comments powered by Disqus