📚 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.
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 |
^ (XOR) para implementar, à mão, uma cifra simétrica simples.(c ^ chave) ^ chave == c, base de toda cifra XOR.&, |, <<, >> e ~ para extrair, ligar, deslocar e inverter bits.==, != e && em expressões impressas, sem if.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
O mesmo do Miniprojeto 01: gcc 8 ou mais novo. No Windows, rode chcp 65001 se os emojis aparecerem quebrados.
🎯 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
====================================================
🎯 Objetivo: ver que aplicar o mesmo XOR duas vezes desfaz a cifra.
⌨️ Faça:
cifra1 a cifra4 como unsigned char, com letraN ^ chave.decifra1 a decifra4 com cifraN ^ chave.Cifrado com %02x e a linha Decifrado com %c.decifra1 == letra1 com %d e, depois, as 4 comparações unidas com &&.💡 Faça o cast
(unsigned int)antes de imprimir umunsigned charcom%x. Numa função variádica como oprintf, ounsigned charé promovido aint, e o%xespera umunsigned 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.
🎯 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.
✅ 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
====================================================
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.
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.
📋 Projetos do curso de C | 📚 Teoria do Capítulo 04 | 🗂️ Hub de projetos