Programe como linguagem de alto nível, execute como C.
Visão Geral • Comunidade • Início Rápido • Ecossistema • Referência da Linguagem • Biblioteca Padrão • Ferramentas
Zen C é uma moderna linguagem de programação de sistemas que compila para GNU C/C11 legível para humanos. Oferece um rico conjunto de funcionalidades, incluindo inferência de tipos, correspondência de padrões, genéricos, traits, async/await, e gerenciamento manual de memória com capacidades RAII - tudo enquanto mantém 100% de compatibilidade ABI com C.
Participe das discussões, compartilhe demos, pergunte, ou reporte bugs no servidor oficial de Discord da Zen C!
- Discord: Clique aqui
- RFCs: Propor funcionalidades
O projeto Zen C consiste em vários repositórios. Abaixo você pode encontrar os principais:
| Repositório | Descrição | Estado |
|---|---|---|
| zenc | O compilador core de Zen C (zc), CLI e a Biblioteca Padrão. |
Desenvolvimento Ativo |
| docs | A documentação técnica oficial e a especificação da linguagem. | Ativo |
| rfcs | O repositório de Pedido de Comentários (RFC). Molde o futuro da linguagem. | Ativo |
| vscode-zenc | Extensão oficial do VS Code (Destaque de sintaxe, Snippets). | Alpha |
| www | Código fonte de zenc-lang.org. |
Ativo |
| awesome-zenc | Uma lista curada de exemplos fantásticos de Zen C. | Em crescimento |
Confira estes projetos construídos com Zen C:
- ZC-pong-3ds: Um clone de Pong para Nintendo 3DS.
- zen-c-parin: Um exemplo básico usando Zen C com Parin.
- almond: Um navegador web minimalista escrito em Zen C.
git clone https://github.com/zenc-lang/zenc.git
cd Zen-C
make clean # remove arquivos de build antigos
make
sudo make installZen C tem suporte nativo completo para Windows (x86_64). Você pode compilar usando o script em lote (batch) fornecido com GCC (MinGW):
build.batIsso construirá o compilador (zc.exe). As operações de Rede, Sistema de Arquivos e Processo são totalmente suportadas através da Camada de Abstração de Plataforma (PAL).
Alternativamente, você pode usar make se tiver um ambiente semelhante ao Unix (MSYS2, Cygwin, git-bash).
Zen C pode ser compilado como um Actually Portable Executable (APE) usando Cosmopolitan Libc. Isso gera um único binário (.com) que executa nativamente em Linux, macOS, Windows, FreeBSD, OpenBSD, e NetBSD, tanto em arquiteturas x86_64 quanto aarch64.
Pré-requisitos:
- Toolchain
cosmocc(precisa estar no seu PATH)
Build & Instalação:
make ape
sudo env "PATH=$PATH" make install-apeArtifacts:
out/bin/zc.com: O compilador portátil de Zen-C. Inclui a biblioteca padrão embutida no executável.out/bin/zc-boot.com: Um instalador bootstrap independente para configurar novos projetos Zen-C.
Uso:
# Executa em qualquer SO suportado
./out/bin/zc.com build hello.zc -o hello# Compila e executa
zc run hello.zc
# Build do executável
zc build hello.zc -o hello
# Shell interativo
zc repl
# Mostrar Fatos Zen
zc build hello.zc --zenVocê pode configurar ZC_ROOT para especificar a localização da Biblioteca Padrão (imports padrões como import "std/vec.zc"). Isso permite que você execute zc de qualquer diretório.
export ZC_ROOT=/path/to/Zen-CZen C distingue constantes em tempo de compilação e variáveis em tempo de execução.
Valores que existem apenas em tempo de compilação (encapsuladas no código). Utilize para tamanhos de arrays, configurações fixas e números mágicos.
def MAX_SIZE = 1024;
let buffer: char[MAX_SIZE]; // Tamanho de array válido
Armazenam localizações na memória. Podem ser mutáveis (let) ou apenas leitura (const).
let x = 10; // Mutável
x = 20; // OK
let y: const int = 10; // Apenas leitura (tipo qualificado)
// y = 20; // Erro: atribuição a const não permitida
Tip
Inferência de Tipo: Zen C automaticamente infere tipos de variáveis inicializadas. Compila para C23 auto em compiladores suportados, ou para __auto_type da extensão GCC alternativamente.
| Tipo | Equivalente em C | Descrição |
|---|---|---|
int, uint |
int, unsigned int |
Inteiro padrão da plataforma |
I8 .. I128 ou i8 .. i128 |
int8_t .. __int128_t |
Inteiros sinalizados de tamanho fixo |
U8 .. U128 ou u8 .. u128 |
uint8_t .. __uint128_t |
Inteiros não-sinalizados de tamanho fixo |
isize, usize |
ptrdiff_t, size_t |
Inteiros do tamanho de ponteiro |
byte |
uint8_t |
Alias para U8 |
F32, F64 ou f32, f64 |
float, double |
Números de ponto flutuante |
bool |
bool |
true (verdadeiro) ou false (falso) |
char |
char |
Caractere único |
string |
char* |
C-string (terminada em NULL) |
U0, u0, void |
void |
Tipo vazio |
iN (por exemplo, i256) |
_BitInt(N) |
Inteiro sinalizado de largura de bit arbitrária (C23) |
uN (por exemplo, u42) |
unsigned _BitInt(N) |
Inteiro não-sinalizado de largura de bit arbitrária (C23) |
- Inteiros: Decimal (
123), Hex (0xFF), Octal (0o755), Binário (0b1011).- Nota: Números com zeros à esquerda são tratados como decimais (
0123é123), diferente de C. - Nota: Números podem conter sublinhados para legibilidade (
1_000_000,0b_1111_0000).
- Nota: Números com zeros à esquerda são tratados como decimais (
- Flutuantes: Padrão (
3.14), Científico (1e-5,1.2E3). Números de ponto flutuante também suportam sublinhados (3_14.15_92).
Arrays de tamanho fixo com semântica de valores.
def SIZE = 5;
let ints: int[SIZE] = [1, 2, 3, 4, 5];
let zeros: [int; SIZE]; // Inicialização-Zero
Agrupa múltiplos valores juntos, acessa elementos por índice.
let pair = (1, "Hello");
let x = pair.0; // 1
let s = pair.1; // "Hello"
Retorno Múltiplo de Valores
Funções podem retornar tuplas para fornecer múltiplos resultados:
fn add_and_subtract(a: int, b: int) -> (int, int) {
return (a + b, a - b);
}
let result = add_and_subtract(3, 2);
let sum = result.0; // 5
let diff = result.1; // 1
Desestruturação
Tuplas podem ser desestruturadas diretamente em variáveis:
let (sum, diff) = add_and_subtract(3, 2);
// sum = 5, diff = 1
Desestruturação tipada permite anotações de tipo explícitas:
let (a: string, b: u8) = ("hello", 42);
let (x, y: i32) = (1, 2); // Misto: x inferido, y explícito
Estruturas de dados com campos de bit opcionais.
struct Point {
x: int;
y: int;
}
// Inicialização de Struct
let p = Point { x: 10, y: 20 };
// Bitfields
struct Flags {
valid: U8 : 1;
mode: U8 : 3;
}
Note
Structs usam Semântica de Move por padrão. Campos podem ser acessados via . mesmo em ponteiros (Auto-Dereferência).
Você pode definir um struct como opaque para restringir acesso aos seus campos exclusivamente ao módulo que o define, enquanto ainda permite que o struct seja alocado na pilha com tamanho conhecido.
// Em user.zc
opaque struct User {
id: int;
name: string;
}
fn new_user(name: string) -> User {
return User{id: 1, name: name}; // OK: Dentro do módulo
}
// Em main.zc
import "user.zc";
fn main() {
let u = new_user("Alice");
// let id = u.id; // Erro: Acesso ao campo privado 'id' não permitido
}
Unions etiquetadas (tipos Sum) capazes de armazenar dados.
enum Shape {
Circle(float), // Armazena o raio
Rect(float, float), // Armazena largura e altura
Point // Sem dados
}
Unions C padrão (acesso inseguro).
union Data {
i: int;
f: float;
}
Tipos de vetores SIMD nativos usando extensões de vetores do GCC/Clang. Anote um struct com @vector(N) para definir um vetor de N elementos.
import "std/simd.zc";
fn main() {
let a = f32x4{v: 1.0}; // Broadcast: {1.0, 1.0, 1.0, 1.0}
let b = f32x4{1.0, 2.0, 3.0, 4.0}; // Inicialização por elemento
let c = a + b; // Adição por elemento
let x = c[0]; // Acesso ao elemento (float)
}
Operadores aritméticos (+, -, *, /) e bitwise (&, |, ^) funcionam por elemento. Veja std/simd.zc para os tipos predefinidos.
Cria um novo nome para um tipo existente.
alias ID = int;
alias PointMap = Map<string, Point>
alias OpFunc = fn(int, int) -> int
Nota: O ponto e vírgula final é opcional para aliases de tipo.
Você pode definir um alias como opaque para criar um novo tipo que é distinto de seu tipo subjacente fora do módulo que o define. Isso fornece forte encapsulamento e segurança de tipos sem o overhead de runtime de um struct wrapper.
// Em library.zc
opaque alias Handle = int;
fn make_handle(v: int) -> Handle {
return v; // Conversão implícita permitida dentro do módulo
}
// Em main.zc
import "library.zc";
fn main() {
let h: Handle = make_handle(42);
// let i: int = h; // Erro: validação de tipo falhou
// let h2: Handle = 10; // Erro: validação de tipo falhou
}
fn add(a: int, b: int) -> int {
return a + b;
}
// Argumentos nomeados são suportados na chamada
add(a: 10, b: 20);
Note
Argumentos nomeados devem seguir estritamente a ordem dos parâmetros. add(b: 20, a: 10) é inválido.
Funções podem ser marcadas como const para impor semântica de apenas leitura. Isso é um qualificador de tipo, não uma constante manifest.
fn print_val(v: const int) {
// v = 10; // Erro: atribuição a const não permitida
println "{v}";
}
Funções podem definir valores-padrão para argumentos trailing. Estes podem ser literais, expressões ou código Zen C válido (como construtores struct).
// Valor padrão simples
fn increment(val: int, amount: int = 1) -> int {
return val + amount;
}
// Expressão de valor padrão (avaliada no local da chamada)
fn offset(val: int, pad: int = 10 * 2) -> int {
return val + pad;
}
// Valor padrão de struct
struct Config { debug: bool; }
fn init(cfg: Config = Config { debug: true }) {
if cfg.debug { println "Debug Mode"; }
}
fn main() {
increment(10); // 11
offset(5); // 25
init(); // Print "Debug Mode"
}
Funções anônimas que podem capturar seu ambiente.
let factor = 2;
let dobrar = x -> x * factor; // Sintaxe de seta
let full = fn(x: int) -> int { return x * factor; }; // Sintaxe de bloco
// Captura por Referência (Sintaxe de Bloco)
let val = 10;
let modify = fn[&]() { val += 1; };
modify(); // val agora é 11
// Captura por Referência (Sintaxe de Seta)
let modify_arrow = [&] x -> val += x;
modify_arrow(5); // val agora é 16
// Captura por Referência (Sintaxe de Seta com Múltiplos Argumentos)
let sum_into = [&] (a, b) -> val += (a + b);
sum_into(2, 2); // val agora é 20
// Captura por Valor (Padrão)
let original = 100;
let implicita = x -> original + x; // Captura implícita por valor (sem colchetes)
let explicita = [=] x -> original + x; // Captura explícita por valor
// let fail = x -> original += x; // Erro: não é possível atribuir a valor capturado
Zen C suporta ponteiros de função C brutos usando sintaxe fn*. Isso permite interoperabilidade ininterrupta com bibliotecas C que esperam ponteiros de função, sem overhead de fechamento.
// Função recebendo um ponteiro de função bruto
fn set_callback(cb: fn*(int)) {
cb(42);
}
// Função retornando um ponteiro de função bruto
fn get_callback() -> fn*(int) {
return my_handler;
}
// Ponteiros para ponteiros de função são suportados (fn**)
let pptr: fn**(int) = &ptr;
Funções podem aceitar um número variável de argumentos utilizando ... e o tipo va_list.
fn log(lvl: int, fmt: char*, ...) {
let ap: va_list;
va_start(ap, fmt);
vprintf(fmt, ap); // Use C stdio
va_end(ap);
}
if x > 10 {
print("Large");
} else if x > 5 {
print("Medium");
} else {
print("Small");
}
// Condicional Ternária
let y = x > 10 ? 1 : 0;
// If-Expression (para condições complexas)
let categoria = if (x > 100) { "enorme" } else if (x > 10) { "grande" } else { "pequeno" };
Poderosa alternativa ao switch.
match val {
1 => { print "One" },
2 || 3 => { print "Two or Three" }, // OR com ||
4 or 5 => { print "Four or Five" }, // OR com 'or'
6, 7, 8 => { print "Six to Eight" }, // OR com vírgula
10 .. 15 => { print "10 to 14" }, // Range excludente (Legado)
10 ..< 15 => { print "10 to 14" }, // Range excludente (Explícito)
20 ..= 25 => { print "20 to 25" }, // Range inclusivo
_ => { print "Other" },
}
// Desestruturando Enums
match shape {
Shape::Circle(r) => println "Radius: {r}",
Shape::Rect(w, h) => println "Area: {w*h}",
Shape::Point => println "Point"
}
Para inspecionar um valor sem tomar posse (movendo-o), use a palavra-chave ref no padrão. Isso é essencial para tipos que implementam semântica de movimento, como Option, Result e structs non-Copy.
let opt = Some(NonCopyVal{...});
match opt {
Some(ref x) => {
// 'x' é um ponteiro para o valor dentro de 'opt'
// 'opt' NÃO É movido/consumido aqui
println "{x.field}";
},
None => {}
}
// Range
for i in 0..10 { ... } // Excludente (0 a 9)
for i in 0..<10 { ... } // Excludente (Explícito)
for i in 0..=10 { ... } // Inclusivo (0 a 10)
for i in 0..10 step 2 { ... }
for i in 10..0 step -1 { ... } // Descending loop
// Iterador (Vec ou Iterável Customizado)
for item in vec { ... }
// Enumerado: obtém índice e valor
for i, val in arr { ... } // i = 0, 1, 2, ...
for i, val in 0..10 step 2 { ... } // i = 0, 1, 2, ...; val = 0, 2, 4, ...
// Itera sobre arrays de tamanho fixo diretamente
let arr: int[5] = [1, 2, 3, 4, 5];
for val in arr {
// val é um int
println "{val}";
}
// While
while x < 10 { ... }
// Infinito com label
outer: loop {
if done { break outer; }
}
// Repita N vezes
for _ in 0..5 { ... }
// Guard: Executa else e return se a condição for falsa
guard ptr != NULL else { return; }
// Unless: Se não for verdadeiro
unless is_valid { return; }
Zen C suporta sobrecarga de operadores para structs definidos pelo usuário através da implementação de nomes específicos de métodos.
| Categoria | Operador | Nome do Método |
|---|---|---|
| Aritmético | +, -, *, /, %, ** |
add, sub, mul, div, rem, pow |
| Comparação | ==, != |
eq, neq |
<, >, <=, >= |
lt, gt, le, ge |
|
| Bitwise | &, |, ^ |
bitand, bitor, bitxor |
<<, >> |
shl, shr |
|
| Unário | - |
neg |
! |
not |
|
~ |
bitnot |
|
| Índice | a[i] |
get(a, i) |
a[i, j] |
get(a, i, j) |
|
a[i] = v |
set(a, i, v) |
Note
Nota sobre a Igualdade de Strings:
string == stringperforma uma comparação de valores (equivalente astrcmp).char* == char*performa comparação de ponteiros (checa os endereços da memória).- Comparações mistas (e.g.
string == char*) são comparação de ponteiros por padrão.
Exemplo:
impl Point {
fn add(self, other: Point) -> Point {
return Point{x: self.x + other.x, y: self.y + other.y};
}
}
let p3 = p1 + p2; // Chama p1.add(p2)
Exemplo Multi-Índice:
struct Matriz {
data: int[9];
}
impl Matriz {
fn get(self, linha: int, col: int) -> int {
return self.data[linha * 3 + col];
}
}
let m = Matriz{data: [1,0,0, 0,1,0, 0,0,1]};
let val = m[1, 2]; // Chama Matriz.get(m, 1, 2)
Estes operadores são funcionalidades embutidas na linguagem e não podem ser sobrecarregados diretamente.
| Operador | Nome | Descrição |
|---|---|---|
|> |
Pipeline | x |> f(y) des-açucara para f(x, y) |
?? |
Coalescência Null | val ?? default retorna default se val for NULL (ponteiros) |
??= |
Atribuição Null | val ??= init atribui se val for NULL |
?. |
Navegação Segura | ptr?.field acessa o campo apenas se ptr não for NULL |
? |
Operador Try | res? retorna erro se presente (tipos Result/Option) |
Auto-Deferência:
Acesso a campos de ponteiro (ptr.field) e chamadas de métodos (ptr.method()) automaticamente dereferencia o ponteiro, equivalente a (*ptr).field.
Zen C fornece opções versáteis para print no console, incluindo palavras-chave e abreviações concisas.
| Palavra-chave | Descrição |
|---|---|
print |
Imprime na saída padrão (sem newline) |
println |
Imprime na saída padrão (com newline) |
eprint |
Imprime no erro padrão (sem newline) |
eprintln |
Imprime no erro padrão (com newline) |
Zen C permite utilizar literais string diretamente como declarações para print rápido:
| Sintaxe | Equivalente | Descrição |
|---|---|---|
"Hello" |
println "Hello" |
Implicitamente adiciona newline. |
"Hello".. |
print "Hello" |
Sem trailing newline. |
!"Error" |
eprintln "Error" |
Output para stderr. |
!"Error".. |
eprint "Error" |
Output para stderr, sem newline. |
Você pode incorporar expressões diretamente em literais de string usando sintaxe {}. Isso funciona com todos os métodos de print e abreviações de string.
Interpolação de strings em Zen C é implícita: se sua string contém {...}, ela será automaticamente analisada como uma string interpolada. Você também pode explicitar o uso do prefixo f (e.g., f"...") para forçar a semântica de interpolação.
let x = 42;
let name = "Zen";
println "Value: {x}, Name: {name}";
"Value: {x}, Name: {name}"; // abreviação de println
Escapando Chaves: Use {{ para produzir uma chave literal { e }} para uma } literal:
let json = "JSON: {{\"chave\": \"valor\"}}";
// Saída: JSON: {"chave": "valor"}
Strings Brutas (Raw Strings): Para definir uma string na qual sequências de extrapolação e metacaracteres são completamente ignorados, utilize o prefixo r (e.g., r"..."):
let regex = r"\w+"; // Contêm exatamente \ w +
let raw_json = r'{"chave": "valor"}'; // Não requer escapar chaves
Zen C suporta blocos puros sem preenchimentos usando strings multilinha com o delimitador """. Isso é extremamente útil para escrever linguagens embarcadas (GLSL, HTML) ou para geração de código C em um bloco comptime sem necessidade de interativamente escapar recuos da linha ou interpolação de aspas no interior da string.
De forma similar as string em padrão normal, string multilinha suportam interpolação implícita. Elas também podem ter atributos explicitos através do prefixo para strings puras e impuras (formatação normal):
f"""...""": Explicitamente marca qual deve ser do respectivo tipo bloco de formatação ou String Impura.r"""...""": Explicitamente marca como um bloco literal de String Bruta (nada será processado entre eles ou ignorar caracateres especiais).
let prompt = """
Por favor, insira o seu nome:
Digite "exit" para sair da área ou cancelar.
""";
let mundo = "mundo";
let script = """
fn ola() {
println "olá, {mundo}!";
}
""";
let pure_raw = r"""
Aqui a reprentância da variável de {chaves} é pura sendo só texto, e o \n é só as letras barra-n de modo linear na sua impressão
""";
Zen C suporta uma abreviação para solicitar entrada do usuário usando o prefixo ?.
? "Prompt text": Imprime o prompt (sem newline) e aguarda entrada (lê uma linha).? "Enter age: " (age): Imprime prompt e escaneia entrada para a variávelage.- Especificadores de formato são automaticamente inferidos com base no tipo da variável.
let age: int;
? "How old are you? " (age);
println "You are {age} years old.";
Zen C permite gerenciamento manual de memória com auxílios ergonômicos.
Executa código quando sair do escopo atual. Declarações defer são executadas em ordem LIFO (last-in, first-out - último a entrar, primeiro a sair).
let f = fopen("file.txt", "r");
defer fclose(f);
Warning
Para prevenir comportamento indefinido, declarações de fluxo de controle (return, break, continue, goto) não são permitidas dentro de um bloco defer.
Libera automaticamente a variável quando sair do escopo.
autofree let types = malloc(1024);
Zen C trata tipos com destrutores (como File, Vec, ou ponteiros mallocados) como Recursos. Para prevenir erros de double-free, recursos não podem ser implicitamente duplicados.
- Move by Default: Atribuir uma variável de recurso transfere propriedade. A variável original se torna inválida (Movida).
- Copy Types: Tipos sem destrutores podem optar pelo comportamento
Copy, fazendo da atribuição uma duplicação.
Diagnósticos & Filosofia: Se você vir um erro "Use of moved value", o compilador está dizendo: "Este tipo possui um recurso (como memória ou um handle) e copiá-lo cegamente é inseguro."
Note
Contraste: Diferente de C/C++, Zen C não duplica implicitamente valores que possuem recursos.
Argumentos de Função: Passar um valor para uma função segue as mesmas regras que atribuição: recursos são movidos a menos que passados por referência.
fn process(r: Resource) { ... } // 'r' é movido para a função
fn peek(r: Resource*) { ... } // 'r' é emprestado (referência)
Clonagem Explícita: Se você realmente quiser duas cópias de um recurso, torne isso explícito:
let b = a.clone(); // Chama o método 'clone' do trait Clone
Opt-in Copy (Tipos de Valor): Para tipos pequenos sem destrutores:
struct Point { x: int; y: int; }
impl Copy for Point {} // Opt-in para duplicação implícita
fn main() {
let p1 = Point { x: 1, y: 2 };
let p2 = p1; // Copiado. p1 permanece válido.
}
Implementa Drop para executar lógica de limpeza automaticamente.
impl Drop for MyStruct {
fn drop(self) {
self.free();
}
}
Defina métodos em tipos usando impl.
impl Point {
// Método estático (convenção de construtor)
fn new(x: int, y: int) -> Self {
return Point{x: x, y: y};
}
// Método de instância
fn dist(self) -> float {
return sqrt(self.x * self.x + self.y * self.y);
}
}
Atalho de Self: Em métodos com um parâmetro self, você pode usar .campo como atalho para self.campo:
impl Point {
fn dist(self) -> float {
return sqrt(.x * .x + .y * .y); // Equivalente a self.x, self.y
}
}
Zen C permite definir métodos em tipos primitivos (como int, bool, etc.) usando a mesma sintaxe impl.
impl int {
fn abs(self) -> int {
return *self < 0 ? -(*self) : *self;
}
}
let x = -10;
let y = x.abs(); // 10
let z = (-5).abs(); // 5 (Literals supported)
Defina comportamento compartilhado.
struct Circle { radius: f32; }
trait Drawable {
fn draw(self);
}
impl Drawable for Circle {
fn draw(self) { ... }
}
let circle = Circle{};
let drawable: Drawable = &circle;
Zen C inclui traits padrões que se integram com a sintaxe da linguagem.
Iterable
Implemente Iterable<T> para habilitar loops for-in para seus tipos customizados.
import "std/iter.zc"
// Defina um Iterator
struct MyIter {
curr: int;
stop: int;
}
impl MyIter {
fn next(self) -> Option<int> {
if self.curr < self.stop {
self.curr += 1;
return Option<int>::Some(self.curr - 1);
}
return Option<int>::None();
}
}
// Implemente Iterable
impl MyRange {
fn iterator(self) -> MyIter {
return MyIter{curr: self.start, stop: self.end};
}
}
// Use no Loop
for i in my_range {
println "{i}";
}
Drop
Implemente Drop para definir um destrutor que executa quando o objeto sai de escopo (RAII).
import "std/mem.zc"
struct Resource {
ptr: void*;
}
impl Drop for Resource {
fn drop(self) {
if self.ptr != NULL {
free(self.ptr);
}
}
}
Nota: Se uma variável é movida,
dropNÃO É chamado na variável original. Ela se adere à Semântica de Recursos.
Copy
Trait marcador para optar pelo comportamento Copy (duplicação implícita) em vez de semântica Move. Usado via @derive(Copy).
Caution
Tipos que implementam Copy não devem definir um destrutor (Drop).
@derive(Copy)
struct Point { x: int; y: int; }
fn main() {
let p1 = Point{x: 1, y: 2};
let p2 = p1; // Copiado! p1 permanece válido.
}
Clone
Implemente Clone para permitir duplicação explícita de tipos que possuem recursos.
import "std/mem.zc"
struct MyBox { val: int; }
impl Clone for MyBox {
fn clone(self) -> MyBox {
return MyBox{val: self.val};
}
}
fn main() {
let b1 = MyBox{val: 42};
let b2 = b1.clone(); // Cópia explícita
}
Use use para incorporar outros structs. Você pode misturá-los (achatar campos) ou nomeá-los (aninhar campos).
struct Entity { id: int; }
struct Player {
// Mixin (Sem nome): Achata campos
use Entity; // Adiciona 'id' ao Player diretamente
name: string;
}
struct Match {
// Composição (Nomeado): Aninha campos
use p1: Player; // Acessado via match.p1
use p2: Player; // Acessado via match.p2
}
Templates type-safe para Structs e Funções.
// Struct Genérico
struct Box<T> {
item: T;
}
// Função Genérica
fn identity<T>(val: T) -> T {
return val;
}
// Genéricos Multi-parâmetro
struct Pair<K, V> {
key: K;
value: V;
}
Construído sobre pthreads.
async fn fetch_data() -> string {
// Executa em background
return "Data";
}
fn main() {
let future = fetch_data();
let result = await future;
}
Execute código em tempo de compilação para gerar código ou imprimir mensagens.
comptime {
// Gera código em tempo de compilação (escrito em stdout)
println "let data_compilacao = \"2024-01-01\";";
}
println "Data de compilação: {data_compilacao}";
Funções Auxiliares
Funções especiais disponíveis dentro de blocos comptime:
yield(str)- Emite explicitamente código gerado (alternativa aprintf)compile_error(msg)- Interrompe a compilação com uma mensagem de erro fatalcompile_warn(msg)- Emite um aviso em tempo de compilação (permite continuar a compilação)
comptime {
compile_warn("Gerando código otimizado...");
let ENABLE_FEATURE = 1;
if (ENABLE_FEATURE == 0) {
compile_error("O recurso deve estar habilitado!");
}
println "let FEATURE_ENABLED = 1;";
}
Metadados de Build
Acesse informações de build do compilador em tempo de compilação:
__COMPTIME_TARGET__- String da plataforma:"linux","windows"ou"macos"__COMPTIME_FILE__- Nome do arquivo fonte atual sendo compilado
comptime {
// Geração de código específica da plataforma
println "let PLATFORM = \"{__COMPTIME_TARGET__}\";";
}
println "Executando em: {PLATFORM}";
Dica: Use raw strings (
r"...") em comptime para evitar escapar chaves:code(r"fn test() { return 42; }"). De lo contrario, use{{e}}para escapar chaves em strings regulares.
Incorpore arquivos como tipos especificados.
// Padrão (Slice_char)
let data = embed "assets/logo.png";
// Embed Tipado
let text = embed "shader.glsl" as string; // Incorporado como C-string
let rom = embed "bios.bin" as u8[1024]; // Incorporado como array fixa
let wav = embed "sound.wav" as u8[]; // Incorporado como Slice_u8
Importe plugins de compilação para sintaxe estendida
import plugin "regex"
let re = regex! { ^[a-z]+$ };
Passe macros pré-processamento para o C.
Dica: Para constantes simples, utilize
defem vez disso. Utilize#definequando você precisar de macros pré-processamento em C ou de flags condicionais de compilação.
#define MAX_BUFFER 1024
Use @cfg() para incluir ou excluir condicionalmente qualquer declaração de nível superior com base em flags -D.
// Compilar com: zc build app.zc -DUSE_OPENGL
@cfg(USE_OPENGL)
import "opengl_backend.zc";
@cfg(USE_VULKAN)
import "vulkan_backend.zc";
@cfg(not(USE_OPENGL))
@cfg(not(USE_VULKAN))
fn fallback_init() { println "Nenhum backend selecionado"; }
| Forma | Significado |
|---|---|
@cfg(NAME) |
Incluir se -DNAME estiver definido |
@cfg(not(NAME)) |
Incluir se -DNAME NÃO estiver definido |
@cfg(any(A, B, ...)) |
Incluir se QUALQUER condição for verdadeira (OR) |
@cfg(all(A, B, ...)) |
Incluir se TODAS as condições forem verdadeiras (AND) |
Múltiplos @cfg em uma declaração são combinados com AND. not() pode ser usado dentro de any() e all(). Funciona com qualquer declaração de nível superior: fn, struct, import, impl, raw, def, test, etc.
Decore funções e structs para modificar o comportamento do compilador.
| Atributo | Escopo | Descrição |
|---|---|---|
@must_use |
Fn | Avisa se o valor de retorno é ignorado. |
@deprecated("msg") |
Fn/Struct | Aviso sobre o uso com mensagem. |
@inline |
Fn | Sugere compilador para inline. |
@noinline |
Fn | Previne inline. |
@packed |
Struct | Remove padding entre campos. |
@align(N) |
Struct | Força alinhamento para N bytes. |
@constructor |
Fn | Executa antes de main. |
@destructor |
Fn | Executa após sair de main. |
@unused |
Fn/Var | Suprime avisos de variáveis não utilizadas. |
@weak |
Fn | Linkagem fraca de símbolos. |
@section("name") |
Fn | Coloca código em seção específica. |
@noreturn |
Fn | Função não retorna (e.g. exit). |
@pure |
Fn | Função sem efeitos colaterais (sugestão de otimização). |
@cold |
Fn | Função provavelmente não é executada (sugestão de predição de branch). |
@hot |
Fn | Função é frequentemente executada (sugestão de otimização). |
@export |
Fn/Struct | Exporta símbolo (visibilidade padrão). |
@global |
Fn | CUDA: Entry point do Kernel (__global__). |
@device |
Fn | CUDA: Função de dispositivo (__device__). |
@host |
Fn | CUDA: Função Host (__host__). |
@comptime |
Fn | Função auxiliar disponível para execução em tempo de compilação. |
@cfg(NAME) |
Qualquer | Compilação condicional: inclui apenas se -DNAME for passado. Suporta not(), any(), all(). |
@derive(...) |
Struct | Auto-implementa traits. Supporta Debug, Eq (Smart Derive), Copy, Clone. |
@ctype("type") |
Fn Param | Sobreescreve tipo C gerado para um parâmetro. |
@<custom> |
Any | Passa atributos genéricos para o C (e.g. @flatten, @alias("name")). |
Zen C suporta um sistema poderoso de Atributos Customizados que te permite usar qualquer __attribute__ de GCC/Clang diretamente no seu código. Qualquer atributo que não seja explicitamente reconhecido pelo compilador de Zen C é tratado como um atributo genérico e passado para o código C gerado.
Isso fornece acesso para funcionalidades avançadas do compilador, otimizações, e diretivas de linker sem precisar de suporte explícito para a linguagem núcleo.
Os atributos Zen C são mapeados diretamente para atributos C:
@name→__attribute__((name))@name(args)→__attribute__((name(args)))@name("string")→__attribute__((name("string")))
Zen C fornece "Smart Derives" que respeitam a Semântica de Move (Move Semantics):
@derive(Eq): Gera um método de igualdade que recebe argumentos por referência (fn eq(self, other: T*)).- Ao comparar dois structs non-Copy (
a == b), o compilador automaticamente passabpor referência (&b) para evitar que ele seja movido. - Checagens recursivas de igualdade nos campos também preferem acesso ao ponteiro para prevenir transferência de propriedade.
- Ao comparar dois structs non-Copy (
Zen C fornece suporte de primeira classe para assembly inline, transpilando diretamente para asmde estilo GCC estendido.
Escreva assembly bruto dentro de blocos asm. Strings são concatenadas automaticamente.
asm {
"nop"
"mfence"
}
Use volatile para prevenir otimizações do compilador em assembly com efeitos colaterais.
asm volatile {
"rdtsc"
}
Zen C simplifica a complexa restrição sintática do GCC com associações nomeadas.
// Syntax: : out(variable) : in(variable) : clobber(reg)
// Uses {variable} placeholder syntax for readability
fn add_five(x: int) -> int {
let result: int;
asm {
"mov {x}, {result}"
"add $5, {result}"
: out(result)
: in(x)
: clobber("cc")
}
return result;
}
| Tipo | Sintaxe | Equivalente GCC |
|---|---|---|
| Output | : out(variable) |
"=r"(variable) |
| Input | : in(variable) |
"r"(variable) |
| Clobber | : clobber("rax") |
"rax" |
| Memory | : clobber("memory") |
"memory" |
Nota: Ao utilizar sintaxe Intel (via
-masm=intel), você deve garantir que seu build esteja configurado corretamente (por exemplo,//> cflags: -masm=intel). O TCC não suporta sintaxe assembly da Intel.
Zen C suporta comentários especiais no topo de seu arquivo-fonte para configurar o processo de build sem precisar de um sistema de build complexo ou um Makefile.
| Diretiva | Argumentos | Descrição |
|---|---|---|
//> link: |
-lfoo ou path/to/lib.a |
Link uma biblioteca ou arquivo objeto. |
//> lib: |
path/to/libs |
Adiciona um caminho de busca por bibliotecas (-L). |
//> include: |
path/to/headers |
Adiciona um caminho de inclusão de buscas (-I). |
//> framework: |
Cocoa |
Link para um framework macOS. |
//> cflags: |
-Wall -O3 |
Passa flags arbitrárias para o compilador C. |
//> define: |
MACRO ou KEY=VAL |
Define um macro preprocessador (-D). |
//> pkg-config: |
gtk+-3.0 |
Executa pkg-config e acrescenta --cflags e --libs. |
//> shell: |
command |
Executa um comando shell durante o build. |
//> get: |
http://url/file |
Baixa um arquivo se o arquivo específico não existir. |
1. OS Guarding
Diretivas de prefixo com o nome de um SO para aplicá-las apenas em plataformas específicas.
Prefixos suportados: linux:, windows:, macos: (or darwin:).
//> linux: link: -lm
//> windows: link: -lws2_32
//> macos: framework: Cocoa
2. Expansão de Variáveis de Ambiente
Use a sintaxe ${VAR} para expandir as variáveis de ambiente em suas diretivas.
//> include: ${HOME}/mylib/include
//> lib: ${ZC_ROOT}/std
//> include: ./include
//> lib: ./libs
//> link: -lraylib -lm
//> cflags: -Ofast
//> pkg-config: gtk+-3.0
import "raylib.h"
fn main() { ... }
Zen C reserva as seguintes palavras-chave:
alias, def, enum, fn, impl, import, let, module, opaque, struct, trait, union, use
async, await, break, catch, continue, defer, else, for, goto, guard, if, loop, match, return, try, unless, while
asm, assert, autofree, comptime, const, embed, launch, ref, sizeof, static, test, volatile
true, false, null
Os seguintes identificadores são reservados porque são palavras-chave em C11:
auto, case, char, default, do, double, extern, float, inline, int, long, register, restrict, short, signed, switch, typedef, unsigned, void, _Atomic, _Bool, _Complex, _Generic, _Imaginary, _Noreturn, _Static_assert, _Thread_local
and, or
Zen C oferece duas formas de interagir com código C: Trusted Imports (Forma conveniente) e Explicit FFI (Forma segura/precisa).
Você pode importar um header C diretamente utilizando a palavra-chave import com a extensão .h. Isso trata o header como um módulo e assume que todos os símbolos acessados através dele existem.
//> link: -lm
import "math.h" as c_math;
fn main() {
// Compilador confia na precisão; emite 'cos(...)' diretamente
let x = c_math::cos(3.14159);
}
Prós: Zero boilerplate. Acessa tudo no header imediatamente. Contras: Sem segurança de tipos por parte do Zen C (erros capturados apenas posteriormente, pelo compilador C).
Para checagem estrita de tipos ou quando você não quer incluir o texto de um header, utilize extern fn.
include <stdio.h> // Emite #include <stdio.h> no C gerado
// Define assinatura estrita
extern fn printf(fmt: char*, ...) -> c_int;
fn main() {
printf("Hello FFI: %d\n", 42); // Type checked by Zen C
}
Prós: Zen C garante correspondência de tipos. Contras: Requer declaração manual de funções.
import "file.h": Registra o header como um módulo nomeado. Habilita acesso implícito aos símbolos (por exemplo,file::function()).include <file.h>: Emite puramente#include <file.h>no código C gerado. Não introduz nenhum símbolo ao compilador Zen C; você deve usarextern fnpara acessá-los.
O Zen C inclui a biblioteca padrão (std), que cobre as funcionalidades essenciais.
Navegue pela Documentação da Biblioteca Padrão
Clique para ver todos os módulos da Biblioteca Padrão
| Módulo | Descrição | Docs |
|---|---|---|
std/bigfloat.zc |
Aritmética de ponto flutuante de precisão arbitrária. | Docs |
std/bigint.zc |
Inteiro de precisão arbitrária BigInt. |
Docs |
std/bits.zc |
Operações bit-a-bit de baixo nível (rotl, rotr, etc). |
Docs |
std/complex.zc |
Aritmética de números complexos Complex. |
Docs |
std/vec.zc |
Growable dynamic array Vec<T>. |
Docs |
std/string.zc |
Heap-allocated String type with UTF-8 support. |
Docs |
std/queue.zc |
FIFO queue (Ring Buffer). | Docs |
std/map.zc |
Generic Hash Map Map<V>. |
Docs |
std/fs.zc |
File system operations. | Docs |
std/io.zc |
Standard Input/Output (print/println). |
Docs |
std/option.zc |
Optional values (Some/None). |
Docs |
std/result.zc |
Error handling (Ok/Err). |
Docs |
std/path.zc |
Cross-platform path manipulation. | Docs |
std/env.zc |
Process environment variables. | Docs |
std/net/ |
TCP, UDP, HTTP, DNS, URL. | Docs |
std/thread.zc |
Threads and Synchronization. | Docs |
std/time.zc |
Time measurement and sleep. | Docs |
std/json.zc |
JSON parsing and serialization. | Docs |
std/stack.zc |
LIFO Stack Stack<T>. |
Docs |
std/set.zc |
Generic Hash Set Set<T>. |
Docs |
std/process.zc |
Process execution and management. | Docs |
std/regex.zc |
Expressões Regulares (baseado em TRE). | Docs |
std/simd.zc |
Tipos de vetores SIMD nativos. | Docs |
Zen C inclui um Language Server embutido (zc lsp) e um REPL para aprimorar a experiência do desenvolvimento.
O Zen C Language Server (LSP) suporta funcionalidades padrão de LSP para integração com editores, fornecendo:
- Go to Definition - Vá para definição
- Find References - Encontrar referências
- Hover Information - Informação com sobreposição do ponteiro do mouse
- Completion - Auto-completar (Nomes de Função/Struct, compleção de ponto para métodos/campos)
- Document Symbols - Símbolos de documento (Outline)
- Signature Help - Ajuda de assinatura
- Diagnostics - Diagnóstico (Sintaxe/Erros semânticos)
Para inicializar o servidor da linguagem (tipicamente configurado nas configurações LSP do seu editor):
zc lspEle se comunica via I/O padrão (JSON-RPC 2.0).
O Read-Eval-Print Loop permite que você experimente seu código Zen C interativamente.
- Código Interativo: Escreva expressões ou declarações para avaliação imediata.
- Histórico Persistente: Comandos são salvos em
~/.zprep_history. - Script de Inicialização: Automaticamente carrega comandos de
~/.zprep_init.zc.
| Comando | Descrição |
|---|---|
:help |
Mostra comandos disponíveis. |
:reset |
Reinicia a sessão atual (limpa todas as definições). |
:vars |
Mostra variáveis ativas. |
:funcs |
Mostra funções definidas pelo usuário. |
:structs |
Mostra structs definidos pelo usuário. |
:imports |
Mostra imports ativos. |
:history |
Mostra histórico de entrada da sessão. |
:type <expr> |
Mostra o tipo de uma expressão. |
:c <stmt> |
Mostra o código C gerado para uma declaração. |
:time <expr> |
Faz benchmark de uma expressão (executa 1000 iterações). |
:edit [n] |
Edita comando n (padrão: último) em $EDITOR. |
:save <file> |
Salva a sessão atual em um arquivo .zc. |
:load <file> |
Carrega e executa um arquivo .zc na sessão. |
:watch <expr> |
Observa uma expressão (reavaliada após cada entrada). |
:unwatch <n> |
Remove um watch. |
:undo |
Remove o último comando da sessão. |
:delete <n> |
Remove comando no índice n. |
:clear |
Limpa a tela. |
:quit |
Sai do REPL. |
! <cmd> |
Executa um comando shell (e.g. !ls). |
O Zen C inclui um Servidor de Linguagem integrado para integração com editores.
- Guia de Instalação e Configuração
- Editores Suportados: VS Code, Neovim, Vim, Zed, e qualquer editor capaz de LSP.
Use zc lsp para iniciar o servidor.
Os programas Zen C podem ser depurados usando depuradores C padrão, como LLDB ou GDB.
Para a melhor experiência no VS Code, instale a extensão oficial do Zen C. Para depuração, você pode usar a extensão C/C++ (da Microsoft) ou a CodeLLDB.
Adicione estas configurações ao seu diretório .vscode para habilitar a depuração com um clique:
tasks.json (Tarefa de Compilação):
{
"label": "Zen C: Build Debug",
"type": "shell",
"command": "zc",
"args": [ "${file}", "-g", "-o", "${fileDirname}/app", "-O0" ],
"group": { "kind": "build", "isDefault": true }
}launch.json (Depurador):
{
"name": "Zen C: Debug (LLDB)",
"type": "lldb",
"request": "launch",
"program": "${fileDirname}/app",
"preLaunchTask": "Zen C: Build Debug"
}Zen C foi projetado para funcionar com a maioria dos compiladores C11. Algumas funcionalidades dependem de extensões GNU C, mas estas frequentemente funcionam em outros compiladores. Use a flag --cc para trocar backends.
zc run app.zc --cc clang
zc run app.zc --cc zigClique para ver detalhes do Suporte de Compilador
| Compilador | Taxa de Aprovação | Funcionalidades Suportadas | Limitações Conhecidas |
|---|---|---|---|
| GCC | 100% (Completo) | Todas as Funcionalidades | Nenhuma. |
| Clang | 100% (Completo) | Todas as Funcionalidades | Nenhuma. |
| Zig | 100% (Completo) | Todas as Funcionalidades | Nenhuma. Usa zig cc como compilador C drop-in. |
| TCC | 98% (Alto) | Estruturas, Genéricos, Traits, Pattern Matching | Sem ASM Intel, Sem __attribute__((constructor)). |
Warning
AVISO DE COMPILAÇÃO: Embora Zig CC funcione excelentemente como backend para seus programas Zen C, compilar o próprio compilador Zen C com ele pode verificar, mas produzir um binário instável que falha nos testes. Recomendamos compilar o compilador com GCC ou Clang e usar Zig apenas como backend para seu código operacional.
O comando zig cc do Zig fornece um substituto drop-in para GCC/Clang com excelente suporte de compilação cruzada. Para usar Zig:
# Compila e executa um programa Zen C com Zig
zc run app.zc --cc zig
# Faz build do próprio compilador Zen C com Zig
make zigZen C pode gerar código compatível com C++ com a flag --cpp, permitindo integração sem emendas com bibliotecas C++.
# Compilação direta com g++
zc app.zc --cpp
# Ou transpile para build manual
zc transpile app.zc --cpp
g++ out.c my_cpp_lib.o -o appInclua headers C++ e use blocos raw para código C++:
include <vector>
include <iostream>
raw {
std::vector<int> make_vec(int a, int b) {
return {a, b};
}
}
fn main() {
let v = make_vec(1, 2);
raw { std::cout << "Size: " << v.size() << std::endl; }
}
Nota: A flag
--cpptroca o backend parag++e emite código compatível com C++ (usaautoem vez de__auto_type, sobrecarga de função em vez de_Generic, e casts explícitos paravoid*).
Zen C suporta programação GPU transpilando para CUDA C++. Isso permite que você aproveite poderosas funcionalidades C++ (templates, constexpr) dentro de seus kernels enquanto mantém a sintaxe ergonômica do Zen C.
# Compilação direta com nvcc
zc run app.zc --cuda
# Ou transpile para build manual
zc transpile app.zc --cuda -o app.cu
nvcc app.cu -o app| Atributo | Equivalente CUDA | Descrição |
|---|---|---|
@global |
__global__ |
Função kernel (executa na GPU, chamada do host) |
@device |
__device__ |
Função device (executa na GPU, chamada da GPU) |
@host |
__host__ |
Função host (explicitamente apenas CPU) |
Zen C fornece uma instrução launch limpa para invocar kernels CUDA:
launch kernel_name(args) with {
grid: num_blocks,
block: threads_per_block,
shared_mem: 1024, // Opcional
stream: my_stream // Opcional
};
Isso transpila para: kernel_name<<<grid, block, shared, stream>>>(args);
Use sintaxe de função Zen C com @global e a instrução launch:
import "std/cuda.zc"
@global
fn add_kernel(a: float*, b: float*, c: float*, n: int) {
let i = thread_id();
if i < n {
c[i] = a[i] + b[i];
}
}
fn main() {
def N = 1024;
let d_a = cuda_alloc<float>(N);
let d_b = cuda_alloc<float>(N);
let d_c = cuda_alloc<float>(N);
defer cuda_free(d_a);
defer cuda_free(d_b);
defer cuda_free(d_c);
// ... init data ...
launch add_kernel(d_a, d_b, d_c, N) with {
grid: (N + 255) / 256,
block: 256
};
cuda_sync();
}
Zen C fornece uma biblioteca padrão para operações CUDA comuns para reduzir blocos raw:
import "std/cuda.zc"
// Gerenciamento de memória
let d_ptr = cuda_alloc<float>(1024);
cuda_copy_to_device(d_ptr, h_ptr, 1024 * sizeof(float));
defer cuda_free(d_ptr);
// Sincronização
cuda_sync();
// Indexação de Thread (use dentro de kernels)
let i = thread_id(); // Índice global
let bid = block_id();
let tid = local_id();
Note
Nota: A flag --cuda define nvcc como o compilador e implica modo --cpp. Requer o NVIDIA CUDA Toolkit.
Zen C suporta funcionalidades modernas de C23 quando usa um compilador backend compatível (GCC 14+, Clang 14+, TCC (parcial)).
auto: Zen C automaticamente mapeia inferência de tipo para oautopadrão C23 se__STDC_VERSION__ >= 202300L._BitInt(N): Use tiposiNeuN(e.g.,i256,u12,i24) para acessar inteiros de largura arbitrária do C23.
Zen C pode compilar para Objective-C (.m) usando a flag --objc, permitindo que você use frameworks Objective-C (como Cocoa/Foundation) e sintaxe.
# Compila com clang (ou gcc/gnustep)
zc app.zc --objc --cc clangUse include para headers e blocos raw para sintaxe Objective-C (@interface, [...], @"").
//> macos: framework: Foundation
//> linux: cflags: -fconstant-string-class=NSConstantString -D_NATIVE_OBJC_EXCEPTIONS
//> linux: link: -lgnustep-base -lobjc
include <Foundation/Foundation.h>
fn main() {
raw {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSLog(@"Hello from Objective-C!");
[pool drain];
}
println "Zen C works too!";
}
Note
Nota: Interpolação de strings do Zen C funciona com objetos Objective-C (id) chamando debugDescription ou description.
Nós damos boas-vindas a contribuições! Seja consertando bugs, adicionando documentação ou propondo novas funcionalidades.
Por favor, veja CONTRIBUTING_PT_BR.md para diretrizes detalhadas sobre como contribuir, executar testes e submeter pull requests.
Para instruções sobre relatórios de segurança, por favor veja SECURITY_PT_BR.md.
Este projeto usa bibliotecas de terceiros. Textos completos de licença podem ser encontrados no diretório LICENSES/.
- cJSON (Licença MIT): Usado para parsing e geração JSON no Language Server.
- zc-ape (Licença MIT): O port original Actually Portable Executable do Zen-C por Eugene Olonov.
- Cosmopolitan Libc (Licença ISC): A biblioteca fundadora que torna APE possível.
- TRE (Licença BSD): Usado para o motor de expressões regulares na biblioteca padrão.
- zenc.vim (Licença MIT): O plugin oficial para Vim/Neovim, escrito principalmente por davidscholberg.
Copyright © 2026 Linguagem de Programação Zen C.
Comece sua jornada hoje.
Discord • GitHub • Documentação • Exemplos • RFCs • Contribuir