C23: Um C Um Pouco Melhor

C23, a mais recente revisão do padrão da linguagem C, introduz um conjunto de recursos incrementais como inferência de tipo com `auto`, `typeof`, uma forma de palavra-chave de `static_assert`, sintaxe de inicialização mais limpa e a remoção de construções legadas como trigraphs e definições de função no estilo K&R. Os comentaristas se dividem sobre se essas mudanças melhoram de fato o C: alguns comemoram macros genéricas melhores, aritmética verificada mais segura e maior alinhamento com extensões de compilador já existentes e com C++, enquanto outros veem isso como ajustes superficiais que não resolvem problemas antigos como strings, módulos e gerenciamento de recursos mais seguro. A conversa também situa o C23 em um panorama mais amplo, no qual muitos projetos novos de sistemas favorecem C++ ou Rust, e em que linguagens alternativas (Zig, D, Nim, Ada etc.) competem para oferecer interoperabilidade com C mais segura ou mais ergonômica.

Auto, typeof e “genéricos” em C23

  • O reaproveitamento de auto é visto por alguns como uma escolha estranha; muitos esperam que seja um “não” de estilo em código C sério, ao contrário de C++.
  • Outros argumentam que ele é realmente útil em C:
    • Evita nomes de tipos verbosos e prefixos struct/enum.
    • Ajuda com macros genéricas (por exemplo, SWAP(a,b) usando auto tmp = a;) e com tipos inteiros de largura fixa.
    • Padroniza extensões __auto_type já existentes.
  • typeof também é adicionado; alguns observam que agora você pode escrever const typeof(var1) tmp = var1;.
  • Há debate sobre se _Generic realmente conta como “genéricos”: alguns o veem como sobrecarga/seleção por tipo, não como estruturas de dados paramétricas; outros dizem que ainda atende ao critério de “genérico.”

Outros ajustes de linguagem do C23

  • static_assert torna-se uma palavra-chave; o C11 já tinha _Static_assert e uma macro, mas agora ele pode ser usado sem <assert.h>.
  • func() agora é explicitamente equivalente a func(void), e parâmetros sem nome são permitidos.
  • A inicialização de structs com {} (zero-init) agora é válida (struct foo x = {};), alinhando com C++.
  • A remoção de trigraphs e das antigas declarações de funções no estilo K&R é bem-vinda como uma limpeza de idiossincrasias históricas.
  • Alguns gostariam que o C23 tivesse um recurso defer/RAII embutido; existe uma proposta desse tipo, mas ela ainda é “exploratória.”

Suporte de toolchain e compiladores

  • Uma referência ao cppreference mostra que o GCC 13 tem suporte ao C23 relativamente amplo; o Clang está atrás em vários recursos.
  • Explicações oferecidas: o design modular do LLVM e forks corporativos desaceleram a evolução do front-end; grandes contribuidores focam em backends ou em outras linguagens.
  • O Pelles C supostamente suporta quase todos os recursos do C23, incluindo #embed.
  • Historicamente, o MSVC negligenciava C, mas mais recentemente oferece suporte ao C17 (menos alguns recursos opcionais do C99); o momento para o C23 ainda é incerto.

C vs C++ e filosofia de linguagem

  • Alguns argumentam que C++ já é “um C melhor” e que o C23 é, em grande parte, um retroporte de recursos do C++.
  • Outros respondem que C e C++ hoje servem a domínios diferentes; a complexidade do C++, sua meta-programação e a geração oculta de código são vistas como inadequadas para certos usos embarcados/de baixo nível.
  • As analogias variam: de “C++ é um cybertruck para a bicicleta do C” (criticada como imprecisa) até “C é ferramenta manual, C++ adiciona ferramentas elétricas.”
  • Há debate sobre exceções e RAII em embarcados: alguns dizem que RAII é simples e útil; outros se preocupam com ciclos de vida de objetos menos explícitos.

Headers, módulos e superfície de API

  • Alguns gostariam que o C tivesse módulos/imports de verdade em vez de headers, para evitar duplicação e acelerar builds, talvez com import ao lado do legado #include.
  • Outros gostam da separação entre header e implementação no C para expor claramente uma API pública; observam que isso é ortogonal a o idioma ter ou não um sistema de módulos.
  • Há discussão de que módulos mais fortes poderiam quebrar parte da interoperabilidade entre C e C++, o que é politicamente sensível.

Alternativas memory-safe e FFI com C

  • Um longo subthread explora “linguagens pequenas, estáveis e memory-safe com excelente FFI com C e sem grande perda de desempenho.”
  • Entre as candidatas mencionadas estão Zig, D, Rust, Nim, V, Vala, LuaJIT, Ada, várias Scheme e Lisps, Swift, Julia e Go.
  • Os tradeoffs destacados:
    • Segurança de memória verdadeira geralmente implica GC ou borrowing no estilo Rust; ambos complicam o FFI e/ou a simplicidade.
    • FFI com C fácil e de overhead zero tende a enfraquecer garantias fortes de segurança (bugs podem entrar via C).
    • Vários comentaristas argumentam que a lista exata de desejos talvez seja impossível de satisfazer completamente; no máximo, dá para aproximá-la com compromissos diferentes.