static e inlineComo organizar e proteger funções em C — a base da programação modular
Até agora você provavelmente colocou todas as funções antes de main() para que o compilador as conhecesse. Mas e quando o programa cresce e as funções precisam se chamar mutuamente? A solução é o protótipo.
// Protótipo — apenas a assinatura, terminada com ; float calcularMedia(float a, float b); // Os nomes dos parâmetros são opcionais no protótipo: float calcularMedia(float, float); // equivalente
#include <stdio.h> /* ── Protótipos ───────────────────────────────── */ float calcularMedia(float a, float b); void classificarAluno(float media); /* ── main ──────────────────────────────────────── */ int main() { float n1 = 7.5, n2 = 8.0; float media = calcularMedia(n1, n2); classificarAluno(media); return 0; } /* ── Definições (podem vir depois de main) ─────── */ float calcularMedia(float a, float b) { return (a + b) / 2.0; } void classificarAluno(float media) { if (media >= 7.0) printf("Aprovado (%.1f)\n", media); else printf("Reprovado (%.1f)\n", media); }
Você já usa arquivos .h todo dia: #include <stdio.h> inclui o cabeçalho da biblioteca padrão de I/O. Agora você vai criar os seus próprios.
.h) é um arquivo de texto que contém protótipos de funções, definições de constantes (#define), definições de tipos (typedef, struct) e qualquer outra coisa que precisa ser compartilhada entre arquivos .c. É a interface pública do seu módulo.
/* matematica.h — cabeçalho do módulo de matemática */ /* ── Inclusion guard: evita que o arquivo seja incluído duas vezes ── */ #ifndef MATEMATICA_H #define MATEMATICA_H /* Constantes */ #define PI 3.14159265358979 /* Protótipos das funções públicas */ float calcularMedia(float a, float b); float areaCirculo(float raio); int ehPrimo(int n); #endif /* MATEMATICA_H */
Se dois arquivos .c incluírem o mesmo .h, e um deles incluir o outro, o conteúdo do .h seria inserido duas vezes no mesmo arquivo de compilação, causando erros de "redeclaração". O inclusion guard previne isso:
| Diretiva | Significado |
|---|---|
#ifndef MATEMATICA_H | Se o símbolo MATEMATICA_H ainda não foi definido... |
#define MATEMATICA_H | ...define-o agora (marca que este arquivo já foi lido) |
#endif | Fecha o bloco condicional |
. trocado por _: o arquivo matematica.h usa MATEMATICA_H. Isso garante unicidade entre arquivos do projeto.
/* ─── matematica.h ─── interface (o que o usuário precisa saber) ─── */ #ifndef MATEMATICA_H #define MATEMATICA_H #define PI 3.14159265358979 float calcularMedia(float a, float b); float areaCirculo(float raio); int ehPrimo(int n); #endif /* ─── matematica.c ─── implementação (como funciona por dentro) ─── */ #include "matematica.h" // aspas: arquivo local (não <> de sistema) #include <math.h> float calcularMedia(float a, float b) { return (a + b) / 2.0f; } float areaCirculo(float raio) { return PI * raio * raio; } int ehPrimo(int n) { if (n < 2) return 0; for (int i = 2; i * i <= n; i++) if (n % i == 0) return 0; return 1; }
#include "arquivo.h" vs #include <arquivo.h>"" → o compilador procura primeiro no diretório do projeto (seus próprios headers).<> → o compilador procura apenas nos diretórios padrão do sistema (stdio.h, math.h, etc.).
static — Encapsulamento por ArquivoPor padrão, toda função em C tem ligação externa: qualquer outro arquivo .c pode acessá-la (desde que tenha o protótipo). Às vezes você quer o contrário — uma função que é um detalhe interno, invisível para o resto do programa.
static tem ligação interna: ela existe apenas no arquivo onde foi definida. Nenhum outro arquivo pode chamá-la — mesmo que tente incluir um protótipo.
/* ─── validacao.c ─── */ #include <stdio.h> /* Função PRIVADA — auxiliar interna, não exportada */ static int ehValido(int valor) { return valor >= 0 && valor <= 100; } /* Função PÚBLICA — visível para outros arquivos */ float calcularMedia(int a, int b) { if (!ehValido(a) || !ehValido(b)) { printf("Valor fora do intervalo [0,100]!\n"); return -1.0f; } return (a + b) / 2.0f; }
| Aspecto | Função normal | Função static |
|---|---|---|
| Visibilidade | Todo o programa (ligação externa) | Apenas o arquivo onde está definida |
| Conflito de nomes | Dois arquivos não podem ter funções com o mesmo nome | Dois arquivos podem ter funções static com o mesmo nome |
| Aparece no .h? | ✅ Deve ter protótipo no .h | ❌ Nunca deve aparecer no .h |
| Analogia em Java | Método public |
Método private |
static qualquer função auxiliar que não precisa ser conhecida fora do seu arquivo. Isso previne conflitos de nomes em projetos grandes e deixa a API pública mais limpa.
/* ─── cadastro.c ─── */ #include "cadastro.h" #include <string.h> #include <stdio.h> /* Auxiliares estáticas — não aparecem no cadastro.h */ static int nomeValido(const char *nome) { return strlen(nome) >= 3 && strlen(nome) <= 50; } static int idadeValida(int idade) { return idade >= 0 && idade <= 130; } /* Função pública */ int cadastrarPessoa(const char *nome, int idade) { if (!nomeValido(nome)) { printf("Nome inválido: '%s'\n", nome); return 0; } if (!idadeValida(idade)) { printf("Idade inválida: %d\n", idade); return 0; } printf("Cadastrado: %s, %d anos\n", nome, idade); return 1; }
static inline — Otimização sem Perda de ClarezaToda chamada de função tem um custo: o programa precisa salvar o estado atual, desviar para o código da função, executar, e retornar. Para funções muito pequenas e chamadas com alta frequência (dentro de loops), esse overhead pode ser significativo.
inline é uma sugestão ao compilador para que ele substitua a chamada da função pelo seu código diretamente no ponto da chamada — eliminando o overhead da chamada. A combinação static inline é a forma mais segura e recomendada em C.
#include <stdio.h> /* Função static inline — ideal para operações pequenas e frequentes */ static inline int quadrado(int x) { return x * x; } static inline float celsius_para_fahrenheit(float c) { return c * 9.0f / 5.0f + 32.0f; } static inline int max(int a, int b) { return (a > b) ? a : b; } int main() { int soma = 0; for (int i = 1; i <= 100; i++) soma += quadrado(i); // O compilador pode expandir o código aqui printf("Soma dos quadrados de 1 a 100: %d\n", soma); printf("37°C = %.1f°F\n", celsius_para_fahrenheit(37.0f)); printf("max(15, 23) = %d\n", max(15, 23)); return 0; }
inline — e quando não usar✅ Use static inline |
❌ Não use inline |
|---|---|
| Funções com 1 a 5 linhas | Funções com loops, switch ou recursão |
| Operações matemáticas simples | Funções raramente chamadas |
| Funções chamadas dentro de loops críticos | Funções que precisam de endereço de memória fixo |
| Conversões de unidade (ex: graus, bytes) | Funções longas (o compilador provavelmente ignorará o hint) |
inline é apenas uma sugestão: O compilador é livre para ignorá-la. Não use inline com a expectativa de que sempre haverá expansão — use porque o código fica mais claro e o compilador pode aproveitar. A diferença real de performance só importa em loops executados milhões de vezes.
Muita gente usa #define para mini-funções como #define QUAD(x) ((x)*(x)). Isso funciona, mas tem armadilhas. A versão static inline é mais segura:
/* ❌ Problema com #define — efeito colateral */ #define QUAD(x) ((x)*(x)) int i = 3; int r = QUAD(i++); // expande para (i++)*(i++) — incrementa i DUAS vezes! /* ✅ Correto com static inline */ static inline int quadrado(int x) { return x * x; } int r2 = quadrado(i++); // i++ ocorre UMA vez, como esperado
| Ferramenta | Onde fica | Para que serve | Analogia Java |
|---|---|---|---|
| Protótipo | Topo do .c ou no .h |
Informa assinatura ao compilador antes da definição | Declaração de método em interface |
Arquivo .h |
Arquivo separado | Interface pública: protótipos, constantes, tipos | Arquivo de interface / API pública |
| Inclusion guard | Dentro do .h |
Evita inclusão dupla | Não tem equivalente direto |
Função static |
No .c, sem entrar no .h |
Função privada ao arquivo | Método private |
Função static inline |
No .h ou no .c |
Eliminação de overhead de chamada para funções pequenas | Não tem equivalente direto |
main.c + modulo.c + modulo.h juntos.