Operações de bits em C++: Como definir, limpar e alternar um único bit (e não enlouquecer)
Olá, colega! Se você já olhou para um código C++ alheio e viu símbolos estranhos como |, & e ~, e depois se perguntou "por que eles estão fazendo isso?" — você está no lugar certo. Hoje vamos abordar um dos tópicos mais populares (e, honestamente, mais elegantes) da programação: operações de bits. Especificamente, como definir, limpar e alternar um único bit.
Isso não é apenas um exercício acadêmico. Trabalhar com bits é um superpoder que será útil em todos os lugares: desde trabalhar com flags de configuração e periféricos de microcontroladores até otimizar o armazenamento de dados em jogos ou bancos de dados. No Stack Overflow, essa pergunta acumulou centenas de milhares de visualizações — o que significa que é realmente importante.
Vamos deixar a teoria chata de lado e ir direto ao ponto. Vamos nessa!
Por que trabalhamos com bits?
Imagine que você tem 8 configurações diferentes (por exemplo, ativar som, exibir dicas, ativar modo noturno, etc.). Você poderia armazená-las em oito variáveis separadas do tipo bool. Mas isso seriam 8 bytes (ou mais). Ou você pode usar um único byte — 8 bits, cada um responsável por uma configuração. Uma economia de memória de 8 vezes — e isso é só o começo.
Operações de bits são uma magia de baixo nível que funciona incrivelmente rápido. O processador as executa em um único ciclo. Para sistemas embarcados, drivers e aplicações de alta carga, isso é crítico.
Em C++, três operadores principais são usados para trabalhar com bits:
|(OU bit a bit) — para definir um bit.&(E bit a bit) — para limpar um bit.^(OU exclusivo bit a bit, XOR) — para alternar um bit.
E mais um operador útil — ~ (NÃO bit a bit), que inverte todos os bits. Ele será útil para limpar bits.
Numeração de bits: vamos combinar desde já
Em programação, os bits são geralmente numerados a partir do zero. O bit menos significativo (Least Significant Bit, LSB) é o bit 0. O bit mais significativo (Most Significant Bit, MSB) é o bit 7 para um byte, 15 para uma palavra (16 bits) e assim por diante.
Neste artigo, usaremos uint8_t (inteiro sem sinal de 8 bits) para maior clareza. Mas todos os exemplos funcionam com int, unsigned int, uint32_t e qualquer outro tipo inteiro.
Como definir um bit (Set bit)
Definir um bit significa torná-lo igual a 1, independentemente do valor anterior.
A maneira mais simples é usar o OU bit a bit com uma máscara. A máscara é um número no qual apenas o bit que queremos alterar está definido.
Fórmula:
número |= (1 << número_do_bit);Vamos detalhar passo a passo:
1 << número_do_bit— desloca o 1 para a esquerda pelo número de posições desejado. Se o número do bit for 3, então1 << 3resulta no binário00001000.número | máscara— a operação OU definirá o bit como 1 se ele era 0, e o manterá como 1 se já era 1.
Exemplo de código em C++:
#include <iostream>#include <cstdint>
int main() { uint8_t flags = 0b00000000; // Inicialmente, todos os bits estão limpos
// Define o 3º bit (contando a partir do zero) flags |= (1 << 3);
// Agora flags = 0b00001000 std::cout << "Após definir o bit 3: " << static_cast<int>(flags) << std::endl;
// Define o 0º bit flags |= (1 << 0); // flags = 0b00001001 std::cout << "Após definir o bit 0: " << static_cast<int>