Carregando
0xE0Lição 15 de 20

Escrevendo C como um profissional

Os hábitos, as ferramentas e os truques que separam o código que funciona hoje do código que continua funcionando.

12 min Questionário com 5 perguntas 1 exercício de código
Ao final desta lição, você saberá
  • Dividir um programa em arquivos .c e .h com include guards
  • Usar avisos, sanitizers e um depurador para encontrar bugs cedo
  • Aplicar hábitos defensivos: const, verificação de limites e posse clara da memória

Agora você conhece o núcleo do C. Esta última aula trata de como os programadores de C experientes trabalham, porque em C são os hábitos que mantêm os programas seguros. Nada disto é extra - é o que "saber C" significa na prática.

Dividindo um programa em arquivos

Quando um programa passa de algumas centenas de linhas, divida-o em módulos: um cabeçalho (.h) que declara o que o módulo oferece e um arquivo-fonte (.c) que o implementa.

stats.h
1#ifndef STATS_H
2#define STATS_H
3
4#include <stddef.h>
5
6double mean(const double values[], size_t count);
7double maximum(const double values[], size_t count);
8
9#endif
stats.c
1#include "stats.h"
2
3double mean(const double values[], size_t count) {
4    double total = 0.0;
5    for (size_t i = 0; i < count; i++) {
6        total += values[i];
7    }
8    return count > 0 ? total / count : 0.0;
9}
10
11double maximum(const double values[], size_t count) {
12    double best = values[0];
13    for (size_t i = 1; i < count; i++) {
14        if (values[i] > best) {
15            best = values[i];
16        }
17    }
18    return best;
19}
  • O main.c então escreve #include "stats.h" (aspas para os seus próprios cabeçalhos, sinais de menor/maior para os do sistema) e chama mean.
  • As linhas #ifndef STATS_H / #define STATS_H / #endif são um include guard: se o cabeçalho for incluído duas vezes, a segunda cópia é pulada.
  • Gere com gcc -Wall -Wextra main.c stats.c -o app. Projetos maiores usam um Makefile (ou CMake) para que só os arquivos alterados sejam recompilados.
  • As funções privadas de um arquivo devem ser marcadas como static, o que as esconde dos outros arquivos.

Deixe as ferramentas pegarem os bugs

FerramentaPegaComo
Avisos do compiladortipos que não combinam, variáveis não usadas, returns faltando, = vs. ==-Wall -Wextra (e -Werror para transformá-los em erros)
AddressSanitizeracesso fora dos limites, uso depois do free, vazamentos-fsanitize=address -g
UndefinedBehaviorSanitizeroverflow com sinal, deslocamentos inválidos, ponteiros desalinhados-fsanitize=undefined
Depurador (gdb / lldb)onde e por que travou; avançar linha por linhacompile com -g, rode gdb ./app
Analisadores estáticosbugs visíveis sem rodarclang --analyze, cppcheck

Hábitos defensivos

  • Inicialize tudo. Variáveis e ponteiros recebem um valor ao serem declarados.
  • Carregue os tamanhos junto com os dados. Todo parâmetro array vem com o seu tamanho; use sizeof em vez de números fixos.
  • Use funções com limite. snprintf, fgets, %99s no scanf - nunca uma escrita sem limite.
  • Verifique os valores de retorno. malloc, fopen, scanf e companhia dizem quando falham; preste atenção.
  • Deixe a posse óbvia. Para cada malloc, deve ficar claro qual função chama o free. Comente onde não for óbvio.
  • Use const à vontade. Ele documenta a intenção e transforma escritas acidentais em erros de compilação.
  • Mantenha as funções pequenas. Funções pequenas são mais fáceis de testar, e os bugs têm menos lugares para se esconder.

Para onde ir agora

  • Leia The C Programming Language (K&R). Curto, preciso e ainda o clássico.
  • Construa algo de verdade: uma aventura de texto, uma lista de tarefas que salva num arquivo, um shell minúsculo, um Jogo da Vida, uma ferramenta de hex dump.
  • Aprenda estruturas de dados em C: listas ligadas, pilhas, tabelas hash - agora você tem todas as ferramentas (structs, ponteiros, malloc) para construí-las.
  • Explore sistemas: conceitos de sistemas operacionais, chamadas de sistema do Linux ou microcontroladores com um Arduino ou um Raspberry Pi Pico.
  • Pergunte e ajude na discussão abaixo de cada aula. Explicar uma ideia para outra pessoa é o jeito mais rápido de encontrar as lacunas no seu próprio entendimento.

Principais conclusões

  • Divida os programas em .h (declarações, com include guards) e .c (definições); marque como static as funções privadas de um arquivo.

  • Ligue os avisos e os sanitizers desde o primeiro dia e aprenda a usar um depurador - eles encontram a maioria dos bugs mais rápido do que você.

  • Inicializar, limitar, verificar e definir a posse: os hábitos defensivos que tornam os programas em C seguros.

Quiz da aula

5 perguntas · aprovação com 4 acertos · até 50 XP

Ao passar, você conclui a aula e mantém sua sequência. As perguntas erradas voltarão em sessões de revisão.

Pratique: escreva código em C

Estes exercícios rodam de verdade. Escreva o programa, clique em “Executar testes” e leia o que o compilador informa: aprender a ler as mensagens do compilador é metade do aprendizado de C.

Exercício 1

Uma saudação com limite

+25 XP

Implemente void make_greeting(char *out, size_t size, const char *name) para que escreva Hello, <name>! em out sem nunca escrever mais que size bytes (truncando se necessário). Use snprintf.

A main lê um nome e a chama com um buffer pequeno de 16 bytes, então nomes longos precisam ser cortados com segurança. Para Ada, imprima Hello, Ada!; para Bartholomew, imprima Hello, Bartholo (15 caracteres + terminador).

  • Nome curto
  • Nome longo é truncado
main.c
Carregando editor…

Seu código é compilado com gcc 14 (-Wall -Wextra) e executado no Compiler Explorer (godbolt.org), um serviço público gratuito.

Dúvidas sobre esta lição

Travou em algum ponto? Pergunte. Descobriu algo? Compartilhe. Explicar também é uma ótima forma de aprender.

Carregando publicações…