📚 Capítulo do curso: 04 — Operadores, Expressões e Bitwise da Especialização em Sistemas com C. Leia o capítulo antes de começar.

🔐 Miniprojeto C 04 — Calculadora Bitwise e Cifra XOR

Um motor criptográfico XOR que cifra e decifra uma palavra de 4 letras, seguido de uma calculadora que extrai, liga, desloca e inverte bits de uma máscara de 8 permissões.

🔒 Regra de Ouro: até o Capítulo 04 você tem sequência, tipos, E/S e, agora, operadores aritméticos, relacionais, lógicos e bitwise. Ainda sem if, switch, laços ou funções. Aqui os operadores relacionais e lógicos aparecem só como expressões calculadas e impressas com %d, nunca como condição de um desvio. Transformá-las em decisões é o assunto do Miniprojeto 05.

⏱️ Tempo estimado 📦 Você vai entregar ✅ Pronto quando
50 min main.c compila sem avisos e a saída é idêntica à do Passo 4

Diagrama do 🔐 Miniprojeto C 04 — Calculadora Bitwise e Cifra XOR

🎯 Objetivos

📋 O problema

Você está prototipando o núcleo de um motor de criptografia leve para um dispositivo embarcado. O programa cifra a palavra CHAR com uma chave de 1 byte, mostra o texto cifrado em hexadecimal, decifra com a mesma chave e prova que o resultado é idêntico. Depois manipula uma máscara de 8 permissões (0xB4).

ID Requisito
RF01 Compila sem nenhum aviso com gcc -Wall -Wextra -Wpedantic -std=c17.
RF02 Inclui <stdio.h> e <stdlib.h>, usa int main(void) e termina com return EXIT_SUCCESS;.
RF03 Nenhum if, switch, while, for ou função além de main.
RF04 Cifra uma palavra fixa de 4 caracteres com ^ e uma chave fixa de 1 byte, uma operação por caractere.
RF05 Mostra o original, o cifrado (em hexadecimal) e o decifrado, que deve ser idêntico ao original.
RF06 Usa pelo menos 4 operadores bitwise diferentes entre &, |, <<, >> e ~ sobre a máscara.
RF07 Imprime com %d pelo menos uma expressão relacional ou lógica (==, !=, &&, ||), fora de qualquer if.
graph LR
    A["main() inicia"] --> B["Cifra XOR\nletra ^ chave (4x, sem laco)"]
    B --> C["Exibe original, cifrado (hex), decifrado"]
    C --> D["Verificacao ==/&&\n(expressao impressa com %d)"]
    D --> E["Mascara de permissoes 0xB4\n& | << >> ~"]
    E --> F["return EXIT_SUCCESS"]

    style B fill:#0284c7,stroke:#38bdf8,color:#ffffff
    style D fill:#7c3aed,stroke:#a78bfa,color:#ffffff
    style E fill:#0d9488,stroke:#2dd4bf,color:#ffffff
    style F fill:#059669,stroke:#34d399,color:#ffffff

🧰 Ambiente

O mesmo do Miniprojeto 01: gcc 8 ou mais novo. No Windows, rode chcp 65001 se os emojis aparecerem quebrados.


Passo 1 — Compilar o esqueleto

🎯 Objetivo: partir de um código que compila e já mostra os dados de entrada.

⌨️ Faça: crie a pasta c_mini_04, salve o código abaixo como main.c e rode:

gcc -Wall -Wextra -Wpedantic -std=c17 main.c -o app
./app          # Linux/macOS
.\app.exe      # Windows (PowerShell)

📄 src/esqueleto.c

/*
 * Miniprojeto 04: Calculadora Bitwise e Motor Criptografico XOR
 * Regra: sequencia + operadores aritmeticos/relacionais/logicos/bitwise.
 * Ainda SEM if, switch, lacos ou funcoes extras.
 */
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    // ---- Bloco 1: cifra XOR de uma palavra fixa de 4 caracteres ----
    unsigned char letra1 = 'C';
    unsigned char letra2 = 'H';
    unsigned char letra3 = 'A';
    unsigned char letra4 = 'R';
    unsigned char chave = 0x5A; // chave fixa de 1 byte

    // TODO 1: calcule cifra1..cifra4 = letraN ^ chave

    // TODO 2: calcule decifra1..decifra4 = cifraN ^ chave
    // (deve reproduzir letra1..letra4 originais)

    printf("====================================================\n");
    printf(" MOTOR CRIPTOGRAFICO XOR - PALAVRA: CHAR\n");
    printf("====================================================\n");
    printf("Original  : %c%c%c%c  (chave = 0x%02x)\n", letra1, letra2, letra3, letra4,
           (unsigned int)chave);
    // TODO 3: imprima o cifrado (em hex, com %02x) e o decifrado

    // TODO 4: imprima uma expressao relacional (ex: decifra1 == letra1) com %d
    // TODO 5: imprima uma expressao logica combinando as 4 comparacoes com &&

    printf("----------------------------------------------------\n");
    printf(" CALCULADORA BITWISE - MASCARA DE 8 PERMISSOES\n");
    printf("----------------------------------------------------\n");

    unsigned char permissoes = 0xB4; // 1011 0100

    // TODO 6: use & para extrair um bit especifico da mascara
    // TODO 7: use | para ligar um bit sem afetar os demais
    // TODO 8: use << para deslocar os bits para a esquerda
    // TODO 9: use >> para deslocar os bits para a direita
    // TODO 10: use ~ para inverter todos os bits (mascare com 0xFF)

    printf("permissoes             = 0x%02x\n", (unsigned int)permissoes);
    // TODO 11: imprima cada resultado em hexadecimal (%02x), alinhado como a linha acima

    printf("====================================================\n");

    return EXIT_SUCCESS;
}

✅ Checkpoint: zero avisos, e a saída é:

🖥️ Saída esperada:

====================================================
 MOTOR CRIPTOGRAFICO XOR - PALAVRA: CHAR
====================================================
Original  : CHAR  (chave = 0x5a)
----------------------------------------------------
 CALCULADORA BITWISE - MASCARA DE 8 PERMISSOES
----------------------------------------------------
permissoes             = 0xb4
====================================================

Passo 2 — Cifrar e decifrar (TODO 1 a 5)

🎯 Objetivo: ver que aplicar o mesmo XOR duas vezes desfaz a cifra.

⌨️ Faça:

  1. Declare cifra1 a cifra4 como unsigned char, com letraN ^ chave.
  2. Declare decifra1 a decifra4 com cifraN ^ chave.
  3. Imprima a linha Cifrado com %02x e a linha Decifrado com %c.
  4. Imprima decifra1 == letra1 com %d e, depois, as 4 comparações unidas com &&.

💡 Faça o cast (unsigned int) antes de imprimir um unsigned char com %x. Numa função variádica como o printf, o unsigned char é promovido a int, e o %x espera um unsigned int.

✅ Checkpoint: Cifrado : 19 12 1b 08, Decifrado : CHAR e as duas verificações imprimem 1.

Confira a primeira letra no papel: 'C' = 0x43 = 0100 0011 e a chave 0x5A = 0101 1010. O XOR bit a bit dá 0001 1001 = 0x19.

🧯 Se der errado: se algum byte cifrado sai com ffffff na frente (acontece com chaves ou letras que ligam o bit 7, como 0xA5), o valor foi tratado como char com sinal. Declare as cifras como unsigned char e faça o cast para unsigned int no printf.


Passo 3 — Máscara de permissões (TODO 6 a 11)

🎯 Objetivo: usar cada operador bitwise para uma tarefa real sobre flags.

⌨️ Faça: sobre permissoes = 0xB4 (1011 0100), calcule e imprima em hexadecimal:

Operação Expressão Para quê
Extrair o bit 2 permissoes & 0x04 testar uma flag
Ligar o bit 0 permissoes | 0x01 conceder uma permissão sem mexer nas outras
Deslocar 2 à esquerda (unsigned int)permissoes << 2 multiplicar por 4
Deslocar 4 à direita permissoes >> 4 pegar o nibble alto
Inverter (unsigned int)(~permissoes) & 0xFFu complemento, só nos 8 bits

Por fim, imprima bit_exec != 0 com %d.

✅ Checkpoint: 0x04, 0xb5, 0x2d0, 0x0b, 0x4b e 1, nessa ordem.

🧯 Se der errado: se o invertido sai 0xffffff4b, faltou a máscara & 0xFF. O ~ age sobre o int promovido, que tem 32 bits, não 8.


Passo 4 — Conferir com o gabarito

✅ Checkpoint: a saída é idêntica a esta, e o código de retorno é 0 (echo $? ou echo $LASTEXITCODE):

🖥️ Saída esperada:

====================================================
 ⚡ MOTOR CRIPTOGRAFICO XOR - PALAVRA: CHAR
====================================================
Original  : CHAR  (chave = 0x5a)
Cifrado   : 19 12 1b 08
Decifrado : CHAR
Verificacao (decifra1 == letra1) : 1
Verificacao (todos batem, &&)    : 1
----------------------------------------------------
 🧮 CALCULADORA BITWISE - MASCARA DE 8 PERMISSOES
----------------------------------------------------
permissoes             = 0xb4
bit_exec   (& 0x04)    = 0x04
com_delete (| 0x01)    = 0xb5
desloc_esq (<< 2)      = 0x2d0
desloc_dir (>> 4)      = 0x0b
invertido  (~ & 0xFF)  = 0x4b
bit_exec != 0 (relacional): 1
====================================================
🔑 Ver gabarito: src/main.c

📄 src/main.c

/*
 * Miniprojeto 04: Calculadora Bitwise e Motor Criptografico XOR
 * Especializacao em Engenharia de Sistemas em C
 * Regra: sequencia + operadores aritmeticos/relacionais/logicos/bitwise.
 */
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    // ---- Bloco 1: cifra XOR de uma palavra fixa de 4 caracteres ----
    unsigned char letra1 = 'C';
    unsigned char letra2 = 'H';
    unsigned char letra3 = 'A';
    unsigned char letra4 = 'R';
    unsigned char chave = 0x5A; // chave fixa de 1 byte (90 em decimal)

    unsigned char cifra1 = letra1 ^ chave;
    unsigned char cifra2 = letra2 ^ chave;
    unsigned char cifra3 = letra3 ^ chave;
    unsigned char cifra4 = letra4 ^ chave;

    // Decifrar = aplicar o MESMO xor com a MESMA chave outra vez:
    // (c ^ chave) ^ chave == c, pois x ^ chave ^ chave == x ^ 0 == x
    unsigned char decifra1 = cifra1 ^ chave;
    unsigned char decifra2 = cifra2 ^ chave;
    unsigned char decifra3 = cifra3 ^ chave;
    unsigned char decifra4 = cifra4 ^ chave;

    printf("====================================================\n");
    printf(" ⚡ MOTOR CRIPTOGRAFICO XOR - PALAVRA: CHAR\n");
    printf("====================================================\n");
    printf("Original  : %c%c%c%c  (chave = 0x%02x)\n", letra1, letra2, letra3, letra4,
           (unsigned int)chave);
    printf("Cifrado   : %02x %02x %02x %02x\n",
           (unsigned int)cifra1, (unsigned int)cifra2,
           (unsigned int)cifra3, (unsigned int)cifra4);
    printf("Decifrado : %c%c%c%c\n", decifra1, decifra2, decifra3, decifra4);

    printf("Verificacao (decifra1 == letra1) : %d\n", decifra1 == letra1);
    printf("Verificacao (todos batem, &&)    : %d\n",
           (decifra1 == letra1) && (decifra2 == letra2) &&
           (decifra3 == letra3) && (decifra4 == letra4));

    printf("----------------------------------------------------\n");
    printf(" 🧮 CALCULADORA BITWISE - MASCARA DE 8 PERMISSOES\n");
    printf("----------------------------------------------------\n");

    // Mascara fixa: 1 byte = 8 flags de permissao (bit 0 = LSB)
    unsigned char permissoes = 0xB4; // 1011 0100

    // & extrai um bit especifico (aqui, o bit 2, valor 0x04)
    unsigned char bit_exec = permissoes & 0x04;

    // | liga um bit sem afetar os demais (aqui, liga o bit 0, valor 0x01)
    unsigned char permissoes_com_delete = permissoes | 0x01;

    // << desloca todos os bits para a esquerda (multiplica por 2 por posicao)
    unsigned int deslocado_esquerda = (unsigned int)permissoes << 2;

    // >> desloca todos os bits para a direita (divide por 2 por posicao)
    unsigned char deslocado_direita = permissoes >> 4;

    // ~ inverte todos os bits (complemento); mascaramos com 0xFF para manter
    // apenas os 8 bits de interesse (o int promovido tem mais bits que isso)
    unsigned int invertido = (unsigned int)(~permissoes) & 0xFFu;

    printf("permissoes             = 0x%02x\n", (unsigned int)permissoes);
    printf("bit_exec   (& 0x04)    = 0x%02x\n", (unsigned int)bit_exec);
    printf("com_delete (| 0x01)    = 0x%02x\n", (unsigned int)permissoes_com_delete);
    printf("desloc_esq (<< 2)      = 0x%02x\n", deslocado_esquerda);
    printf("desloc_dir (>> 4)      = 0x%02x\n", (unsigned int)deslocado_direita);
    printf("invertido  (~ & 0xFF)  = 0x%02x\n", invertido);
    printf("bit_exec != 0 (relacional): %d\n", bit_exec != 0);

    printf("====================================================\n");

    return EXIT_SUCCESS;
}

Por que isso importa: a expressão (decifra1 == letra1) && (decifra2 == letra2) && ... já é, em essência, a condição que um if vai avaliar no próximo capítulo. Aqui ela só é calculada e impressa, sem desviar o fluxo. E o deslocamento << 2 deu 0x2d0, que não cabe em 8 bits: foi por isso que o resultado foi guardado num unsigned int.


🏆 Desafio

Troque a palavra por uma de 6 letras, repetindo à mão o bloco de cifra e decifra para os 2 caracteres extras.

✅ Checkpoint: a linha Decifrado mostra a palavra nova, idêntica à original, e a verificação com && (agora com 6 comparações) imprime 1.

O código cresce uma linha por caractere. Um vetor percorrido por um laço resolve isso no Miniprojeto 07, e o Miniprojeto 12 (strings) aplica a mesma cifra a textos de qualquer tamanho.


🧭 Navegação

📋 Projetos do curso de C | 📚 Teoria do Capítulo 04 | 🗂️ Hub de projetos