Rust e C são as duas faces da programação de sistemas. C é a linguagem com meio século de domínio: kernels, drivers, bancos de dados, criptografia e quase toda a infraestrutura que sustenta a internet foram escritos nela. Rust é a resposta moderna ao mesmo problema — controle total de memória e performance nativa, mas com um compilador que rejeita os bugs de memória que custaram décadas de CVEs em C. Em 2026, com o kernel Linux aceitando drivers em Rust e órgãos como a NSA recomendando linguagens memory-safe, a pergunta “C ou Rust?” deixou de ser teórica.
Resposta rápida: mantendo código C legado ou programando chips com SDK só em C → C. Novos projetos de sistemas, CLIs, backends de performance e componentes nativos → Rust. Novo driver ou módulo de um sistema existente em C → Rust ligado via FFI. Este comparativo cobre performance, segurança de memória, concorrência, toolchain, interoperabilidade, embedded e mercado de trabalho no Brasil — a versão estendida do nosso artigo técnico Rust vs C.
Resposta rápida
| Situação | Escolha inicial | Por quê |
|---|---|---|
| Manter/ampliar código C legado auditorado | C | reescrita tem risco e custo que raramente se pagam |
| Biblioteca nativa para consumir de qualquer linguagem | Rust | expõe ABI C via cbindgen e herda segurança |
| Novo serviço/CLI de sistemas | Rust | Cargo + crates.io aceleram em ordens de magnitude |
| Microcontrolador com SDK apenas em C | C | cobertura de fornecedor ainda é o fator decisivo |
| Driver de kernel Linux novo | Rust | o kernel aceita Rust desde 6.1; C para drivers novos perde vantagem |
| Aprender como a máquina funciona | C | nada ensina ponteiros e layout de memória como C |
| Time com prazos e código que não pode falhar | Rust | bugs de memória não compilam |
Visão Geral
| Aspecto | Rust | C |
|---|---|---|
| Ano de origem | 2015 (1.0) | 1972 |
| Gerenciamento de memória | Ownership e borrowing, verificados em compilação | Manual: malloc/free sob responsabilidade total do programador |
| Segurança de memória | Garantida em código safe | Nenhuma garantia; UB é risco permanente |
| Compiladores | rustc (LLVM) | GCC, Clang e dezenas de derivados |
| Build e pacotes | Cargo + crates.io (100k+ crates) | Make/CMake + bibliotecas vendored ou do SO |
| Concorrência | Threads seguras verificadas, async com Tokio | pthreads, disciplina manual, sem proteção |
| Tratamento de erros | Result/Option explícitos | Códigos de retorno e errno, convenção variável |
| Interoperabilidade | FFI completa com C nas duas direções | ABI universal — toda linguagem fala C |
| Curva de aprendizado | Íngreme no borrow checker, plana depois | Sintaxe pequena, mas a disciplina para acertar leva anos |
| Mercado no Brasil | Nicho com salário premium | Gigante e estável em firmware, automação e telecom |
Performance
C e Rust ocupam o topo absoluto dos benchmarks de linguagens compiladas. Os dois não têm runtime: sem coletor de lixo, sem máquina virtual, sem overhead de chamada. A diferença prática está na previsibilidade — o Rust entrega performance de C sem exigir que o programador manualmente evite invalidar memória.
O mesmo crivo de Eratóstenes nas duas linguagens ilustra o estilo:
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
uint64_t crivo(size_t n) {
uint8_t *composto = calloc(n + 1, 1);
if (!composto) return 0;
for (size_t i = 2; i * i <= n; i++)
if (!composto[i])
for (size_t j = i * i; j <= n; j += i)
composto[j] = 1;
uint64_t total = 0;
for (size_t i = 2; i <= n; i++)
if (!composto[i]) total++;
free(composto);
return total;
}
fn crivo(n: usize) -> u64 {
let mut composto = vec![false; n + 1];
for i in 2..=n {
if i * i > n { break; }
if !composto[i] {
let mut j = i * i;
while j <= n {
composto[j] = true;
j += i;
}
}
}
(2..=n).filter(|&i| !composto[i]).count() as u64
}
Compilados com otimização (-O3 / --release), os dois geram código essencialmente idêntico. O ponto de divergência aparece no código real: em C, cada malloc sem free, cada índice fora da borda e cada ponteiro invalidado é um bug silencioso que pode ou não explodir em produção — o custo de manter performance segura em C é pago em revisão, sanitizers e auditoria. Em Rust, esse custo é pago uma vez, no compilador. Para medir do jeito certo nos dois, vale conhecer o profiling e otimização em Rust e o crate Criterion.
Segurança de Memória: o argumento central
A segurança de memória é a razão de existir do Rust. A Microsoft relatou que ~70% das suas CVEs graves são bugs de memória; o projeto Chromium chegou a números semelhantes. Todos eles — use-after-free, buffer overflow, double free, data race — são impossíveis em Rust safe e rotina em C:
// C: compila, roda e corrói memória silenciosamente
char *buf = malloc(16);
strcpy(buf, "uma string bem maior que 16 bytes"); // overflow
free(buf);
printf("%s\n", buf); // use-after-free
// Rust: nenhum dos erros acima compila
let mut buf = String::with_capacity(16);
buf.push_str("uma string bem maior que 16 bytes"); // realoca com segurança
println!("{buf}"); // uso sempre válido
Em C, ferramentas como AddressSanitizer, Valgrind e a disciplina de ownership documentada em comentários reduzem o risco — mas o compilador aceita o código errado do mesmo jeito. Em Rust, o borrow checker transforma essas classes de bug em erro de compilação. Quando o controle absoluto é necessário (parsers de formato, kernels), o Rust oferece unsafe com escopo explícito — veja nosso guia de unsafe em Rust.
O contraponto honesto: 50 anos de C produziram bibliotecas auditoradas por milhões de olhos (SQLite, OpenSSH, zlib). Código C maduro e bem testado não deve ser reescrito só pela moda — e é aí que entra a interoperabilidade.
Concorrência: pthreads vs threads verificadas
C não tem concorrência na linguagem: usa-se pthreads (POSIX) ou APIs do SO, e toda sincronização — mutexes, condition variables, barreiras — é manual. Um data race em C é UB silencioso; o mesmo código em Rust não compila:
// C: data race compilando sem aviso
void *contador(void *arg) {
long *n = arg;
for (int i = 0; i < 1000000; i++)
(*n)++; // incremento sem lock = corrida
return NULL;
}
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
let contador = Arc::new(Mutex::new(0u64));
let handles: Vec<_> = (0..4)
.map(|_| {
let c = Arc::clone(&contador);
thread::spawn(move || {
for _ in 0..1_000_000 {
*c.lock().unwrap() += 1;
}
})
})
.collect();
for h in handles { h.join().unwrap(); }
println!("{}", *contador.lock().unwrap()); // sempre 4_000_000
}
O compilador Rust impede o envio de dados não Sync entre threads — a tabela de concorrência não é opcional, é lei. Para I/O concorrente massivo, o ecossistema traz async/await com Tokio (veja o guia de async Rust em 2026), algo que em C exigiria epoll manual ou libuv.
Toolchain: Make/CMake vs Cargo
A diferença de produtividade aqui é a maior de todo o comparativo. Em C, montar build multiplataforma significa CMake, Autotools ou Makefiles artesanais, dependências vendored no repositório e documentação espalhada em man pages. Em Rust:
$ cargo new meu-parser && cd meu-parser
$ cargo add serde --features derive
$ cargo build --release
$ cargo test
$ cargo clippy && cargo fmt --check
Um comando cria o projeto, outro adiciona dependência com versionamento semântico, e cargo test roda testes unitários sem infraestrutura extra. O C compensa com ubiquidade: todo sistema operacional, todo CI e todo embedded toolchain do planeta já fala C. Para aprofundar, veja o guia de ferramentas essenciais do Cargo e a instalação via rustup.
Interoperabilidade: o melhor dos dois mundos
O Rust não pede que você escolha um lado — a FFI com C é completa e nas duas direções. Chamar C de Rust com bindgen:
use std::os::raw::c_char;
extern "C" {
fn sqlite3_libversion() -> *const c_char;
}
fn main() {
unsafe {
println!("SQLite {}", std::ffi::CStr::from_ptr(sqlite3_libversion())
.to_string_lossy());
}
}
E expor Rust como biblioteca C, com cbindgen gerando o header:
#[no_mangle]
pub extern "C" fn checksum(dados: *const u8, len: usize) -> u64 {
let fatia = unsafe { std::slice::from_raw_parts(dados, len) };
fatia.iter().fold(0xcbf29ce484222325, |h, &b| (h ^ b as u64).wrapping_mul(0x100000001b3))
}
É esse padrão — núcleo novo em Rust, sistema existente em C — que empresas como Microsoft e a própria comunidade do kernel adotaram. Boa parte das extensões Python de alta performance hoje é exatamente isso: Rust exposto via ABI C, como no nosso guia de PyO3 e Maturin.
Embedded e Kernel Linux
No embedded, o C ainda reina por cobertura: praticamente todo fabricante de MCU entrega SDK, HAL e exemplos em C, e chips menos comuns às vezes nem têm backend LLVM. Mas onde o Rust roda, ele brilha: o framework Embassy traz async sem SO para Cortex-M, os HALs verificados eliminam categorias inteiras de bug de registro e o suporte a #![no_std] dispensa alocador. Para embarcados, comparamos Embassy vs RTIC em detalhe aqui.
No kernel Linux, a trajetória é a mais forte evidência da direção da indústria: o suporte a Rust entrou no 6.1, drivers de rede e GPU em Rust já estão upstream e a adoção no kernel avança a cada release. Nenhum outro projeto C do mundo tem tanto rigor de qualidade — e mesmo ele decidiu que código novo crítico vale mais em Rust.
WebAssembly
Para WebAssembly, a disputa nem é equilibrada: o rustc tem alvo wasm32 de primeira classe, wasm-bindgen e wasm-pack são o padrão da indústria, e os binários Rust rivalizam com C compilado por Emscripten em tamanho — sem a camada de emulação. C na web é possível, mas o fluxo de trabalho do Rust (veja Rust e WebAssembly e o Trunk) é ordens de magnitude mais produtivo. Se o seu componente precisa rodar no navegador, no edge e no servidor, o candidato natural é Rust.
Curva de Aprendizado
C tem sintaxe minúscula — o clássico K&R ensina a linguagem em semanas. O problema é que a linguagem é a parte fácil: o que leva anos é desenvolver a disciplina de gerenciar memória à mão sem introduzir vulnerabilidades. O Rust inverte a curva: as primeiras semanas doem (o borrow checker rejeita código que “parece” razoável), mas o compilador é o professor — depois que o modelo mental de ownership faz clique, o desenvolvimento fica notavelmente fluido, e o debugger vira ferramenta ocasional. Quem já conhece C migra com vantagem: ponteiros, stack vs heap e layout de struct são exatamente os conceitos que o Rust formaliza.
Mercado de Trabalho no Brasil em 2026
O mercado de C no Brasil é enorme e estável: firmware, automação industrial, automotivo, telecom e dispositivos médicos contratam continuamente, especialmente em polos como São José dos Campos, Campinas e Curitiba. O Rust ainda é nicho — mas é nicho com escassez de candidatos: fintechs, empresas de infraestrutura e times de plataforma publicam vagas com salários acima da média backend, como detalhamos no levantamento de salários Rust no Brasil e no guia de carreira Rust 2026. Para quem já programa C (firmware, sistemas), a transição é o upgrade de carreira com melhor custo-benefício — veja o plano de transição para Rust.
Quando escolher cada uma
Escolha C quando
- O alvo é um chip com SDK apenas em C ou sem backend LLVM maduro
- O projeto estende código C auditorado (SQLite, OpenSSL, drivers legados)
- A equipe inteira domina C e o produto é estável — reescrita não se paga
- O requisito é ABI máxima e dependência zero (biblioteca de sistema, boot)
Escolha Rust quando
- O projeto é novo código de sistemas: CLIs, parsers, servidores, agentes
- Segurança de memória é requisito (criptografia, redes, dados sensíveis)
- Você quer async, WASM ou backends de performance sem abrir mão de controle
- O componente será consumido de outras linguagens via FFI
Use as duas quando
- O sistema legado é C e os módulos novos são Rust, ligados por bindgen/cbindgen
- O driver de kernel novo é Rust dentro de um núcleo majoritariamente C
- A biblioteca nativa compartilhada é Rust e o binding de plataforma é C
Conclusão
C e Rust não competem pelo mesmo espaço-tempo: C é o patrimônio — meio século de infraestrutura auditorada que continuará rodando por décadas; Rust é o crescimento — todo código novo de sistemas onde segurança de memória importa. A pergunta certa em 2026 não é “qual substitui qual”, mas “onde cada um reduz risco”. Para o legado, C. Para tudo que é novo e precisa não falhar, Rust — e a FFI entre os dois faz da convivência a arquitetura mais comum, do kernel Linux ao seu próximo crate.
Para continuar, veja os comparativos com Rust vs C++ e Rust vs Zig, o guia como aprender Rust em 2026, os projetos práticos para treinar e o artigo profundo sobre Rust vs C.
Você mantém código C legado, já escreveu componentes em Rust ou usa as duas via FFI? Conte nos comentários como está a convivência no seu projeto!