|
Zen-C
|
Zen C is a modern systems programming language that compiles to human-readable GNU C/C11. It provides a rich feature set including type inference, pattern matching, generics, traits, async/await, and manual memory management with RAII capabilities, all while maintaining 100% C ABI compatibility.
Join the discussion, share demos, ask questions, or report bugs in the official Zen C Discord server!
Zen C can be compiled as an Actually Portable Executable (APE) using Cosmopolitan Libc. This produces a single binary (.com) that runs natively on Linux, macOS, Windows, FreeBSD, OpenBSD, and NetBSD on both x86_64 and aarch64 architectures.
Prerequisites:
cosmocc toolchain (must be in your PATH)Build & Install:
Artifacts:
out/bin/zc.com: The portable Zen-C compiler. Includes the standard library embedded within the executable.out/bin/zc-boot.com: A self-contained bootstrap installer for setting up new Zen-C projects.Usage:
You can set ZC_ROOT to specify the location of the Standard Library (standard imports like import "std/vec.zc"). This allows you to run zc from any directory.
Zen C distinguishes between compile-time constants and runtime variables.
Values that exist only at compile-time (folded into code). Use these for array sizes, fixed configuration, and magic numbers.
Storage locations in memory. Can be mutable or read-only (const).
Type Inference: Zen C automatically infers types for initialized variables. It compiles to C23
autoon supported compilers, or GCC's__auto_typeextension otherwise.
| Type | C Equivalent | Description |
|---|---|---|
int, uint | int32_t, uint32_t | 32-bit signed/unsigned integer |
c_char, c_uchar | char, unsigned char | C char / unsigned char (Interop) |
c_short, c_ushort | short, unsigned short | C short / unsigned short (Interop) |
c_int, c_uint | int, unsigned int | C int / unsigned int (Interop) |
c_long, c_ulong | long, unsigned long | C long / unsigned long (Interop) |
I8 .. I128 or i8 .. i128 | int8_t .. __int128_t | Signed fixed-width integers |
U8 .. U128 or u8 .. u128 | uint8_t .. __uint128_t | Unsigned fixed-width integers |
isize, usize | ptrdiff_t, size_t | Pointer-sized integers |
byte | uint8_t | Alias for U8 |
F32, F64 or f32, f64 | float, double | Floating point numbers |
bool | bool | true or false |
char | char | Single character |
string | char* | C-string (null-terminated) |
U0, u0, void | void | Empty type |
iN (for example, i256) | _BitInt(N) | Arbitrary bit-width signed integer (C23) |
uN (for example, u42) | unsigned _BitInt(N) | Arbitrary bit-width unsigned integer (C23) |
Best Practices for Portable Code
- Use Portable Types (
int,uint,i64,u8, etc.) for all pure Zen C logic.intis guaranteed to be 32-bit signed on all architectures.- Use C Interop Types (
c_int,c_char,c_long) only when interacting with C libraries (FFI). Their size varies by platform and C compiler (e.g.c_longsize differs between Windows and Linux).- Use
isizeandusizefor array indexing and memory pointer arithmetic.
Fixed-size arrays with value semantics.
Group multiple values together, access elements by index.
Multiple Return Values
Functions can return tuples to provide multiple results:
Destructuring
Tuples can be destructured directly into variables:
Data structures with optional bitfields.
Note: Structs use Move Semantics by default. Fields can be accessed via
.even on pointers (Auto-Dereference).
You can define a struct as opaque to restrict access to its fields to the defining module only, while still allowing the struct to be allocated on the stack (size is known).
Tagged unions (Sum types) capable of holding data.
Standard C unions (unsafe access).
Create a new name for an existing type.
You can define a type alias as opaque to create a new type that is distinct from its underlying type outside of the defining module. This provides strong encapsulation and type safety without the runtime overhead of a wrapper struct.
Note: Named arguments must strictly follow the defined parameter order.
add(b: 20, a: 10)is invalid.
Function arguments can be marked as const to enforce read-only semantics. This is a type qualifier, not a manifest constant.
Functions can define default values for trailing arguments. These can be literals, expressions, or valid Zen C code (like struct constructors).
Anonymous functions that can capture their environment.
Zen C supports raw C function pointers using the fn* syntax. This allows seamless interop with C libraries that expect function pointers without closure overhead.
Functions can accept a variable number of arguments using ... and the va_list type.
Powerful alternative to switch.
To inspect a value without taking ownership (moving it), use the ref keyword in the pattern. This is essential for types that implement Move Semantics (like Option, Result, non-Copy structs).
Zen C supports operator overloading for user-defined structs by implementing specific method names.
| Category | Operator | Method Name |
|---|---|---|
| Arithmetic | +, -, *, /, % | add, sub, mul, div, rem |
| Comparison | ==, != | eq, neq |
<, >, <=, >= | lt, gt, le, ge | |
| Bitwise | &, \|, ^ | bitand, bitor, bitxor |
<<, >> | shl, shr | |
| Unary | - | neg |
! | not | |
~ | bitnot | |
| Index | a[i] | get(a, i) |
a[i] = v | set(a, i, v) |
Note on String Equality:
string == stringperforms value comparison (equivalent tostrcmp).char* == char*performs pointer comparison (checks memory addresses).- Mixed comparisons (e.g.
string == char*) default to pointer comparison.
Example:
These operators are built-in language features and cannot be overloaded directly.
| Operator | Name | Description |
|---|---|---|
\|> | Pipeline | x \|> f(y) desugars to f(x, y) |
?? | Null Coalescing | val ?? default returns default if val is NULL (pointers) |
??= | Null Assignment | val ??= init assigns if val is NULL |
?. | Safe Navigation | ptr?.field accesses field only if ptr is not NULL |
? | Try Operator | res? returns error if present (Result/Option types) |
Auto-Dereference: Pointer field access (ptr.field) and method calls (ptr.method()) automatically dereference the pointer, equivalent to (*ptr).field.
Zen C provides versatile options for printing to the console, including keywords and concise shorthands.
print "text": Prints to stdout without a trailing newline.println "text": Prints to stdout with a trailing newline.eprint "text": Prints to stderr without a trailing newline.eprintln "text": Prints to stderr with a trailing newline.Zen C allows you to use string literals directly as statements for quick printing:
"Hello World": Equivalent to println "Hello World". (Implicitly adds newline)"Hello World"..: Equivalent to print "Hello World". (No trailing newline)!"Error": Equivalent to eprintln "Error". (Output to stderr)!"Error"..: Equivalent to eprint "Error". (Output to stderr, no newline)You can embed expressions directly into string literals using {} syntax. This works with all printing methods and string shorthands.
Zen C supports a shorthand for prompting user input using the ? prefix.
? "Prompt text": Prints the prompt (without newline) and waits for input (reads a line).? "Enter age: " (age): Prints prompt and scans input into the variable age.Zen C allows manual memory management with ergonomic aids.
Execute code when the current scope exits. Defer statements are executed in LIFO (last-in, first-out) order.
To prevent undefined behavior, control flow statements (
return,break,continue,goto) are not allowed inside adeferblock.
Automatically free the variable when scope exits.
Zen C treats types with destructors (like File, Vec, or malloc'd pointers) as Resources. To prevent double-free errors, resources cannot be implicitly duplicated.
Copy behavior, making assignment a duplication.Diagnostics & Philosophy: If you see an error "Use of moved value", the compiler is telling you: *"This type owns a resource (like memory or a handle) and blindly copying it is unsafe."*
Contrast: Unlike C/C++, Zen C does not implicitly duplicate resource-owning values.
Function Arguments: Passing a value to a function follows the same rules as assignment: resources are moved unless passed by reference.
Explicit Cloning: If you do want two copies of a resource, make it explicit:
Opt-in Copy (Value Types): For small types without destructors:
Implement Drop to run cleanup logic automatically.
Define methods on types using impl.
Define shared behavior.
Zen C includes standard traits that integrate with language syntax.
Iterable
Implement Iterable<T> to enable for-in loops for your custom types.
Drop
Implement Drop to define a destructor that runs when the object goes out of scope (RAII).
Note: If a variable is moved,
dropis NOT called on the original variable. It adheres to Resource Semantics.
Copy
Marker trait to opt-in to Copy behavior (implicit duplication) instead of Move semantics. Used via @derive(Copy).
Rule: Types that implement
Copymust not define a destructor (Drop).
Clone
Implement Clone to allow explicit duplication of resource-owning types.
Use use to embed other structs. You can either mix them in (flatten fields) or name them (nest fields).
Type-safe templates for Structs and Functions.
Built on pthreads.
Run code at compile-time to generate source or print messages.
Embed files as specified types.
Import compiler plugins to extend syntax.
Pass preprocessor macros through to C.
Tip: For simple constants, use
definstead. Use#definewhen you need C-preprocessor macros or conditional compilation flags.
Decorate functions and structs to modify compiler behavior.
| Attribute | Scope | Description |
|---|---|---|
@must_use | Fn | Warn if return value is ignored. |
@deprecated("msg") | Fn/Struct | Warn on usage with message. |
@inline | Fn | Hint compiler to inline. |
@noinline | Fn | Prevent inlining. |
@packed | Struct | Remove padding between fields. |
@align(N) | Struct | Force alignment to N bytes. |
@constructor | Fn | Run before main. |
@destructor | Fn | Run after main exits. |
@unused | Fn/Var | Suppress unused variable warnings. |
@weak | Fn | Weak symbol linkage. |
@section("name") | Fn | Place code in specific section. |
@noreturn | Fn | Function does not return (e.g. exit). |
@pure | Fn | Function has no side effects (optimization hint). |
@cold | Fn | Function is unlikely to be executed (branch prediction hint). |
@hot | Fn | Function is frequently executed (optimization hint). |
@export | Fn/Struct | Export symbol (visibility default). |
@global | Fn | CUDA: Kernel entry point (__global__). |
@device | Fn | CUDA: Device function (__device__). |
@host | Fn | CUDA: Host function (__host__). |
@comptime | Fn | Helper function available for compile-time execution. |
@derive(...) | Struct | Auto-implement traits. Supports Debug, Eq (Smart Derive), Copy, Clone. |
@ctype("type") | Fn Param | Overrides generated C type for a parameter. |
@<custom> | Any | Passes generic attributes to C (e.g. @flatten, @alias("name")). |
Zen C supports a powerful Custom Attribute system that allows you to use any GCC/Clang __attribute__ directly in your code. Any attribute that is not explicitly recognized by the Zen C compiler is treated as a generic attribute and passed through to the generated C code.
This provides access to advanced compiler features, optimizations, and linker directives without needing explicit support in the language core.
Zen C attributes are mapped directly to C attributes:
@name → __attribute__((name))@name(args) → __attribute__((name(args)))@name("string") → __attribute__((name("string")))Zen C provides "Smart Derives" that respect Move Semantics:
@derive(Eq)**: Generates an equality method that takes arguments by reference (fn eq(self, other: T*)).a == b), the compiler automatically passes b by reference (&b) to avoid moving it.Zen C provides first-class support for inline assembly, transpiling directly to GCC-style extended asm.
Write raw assembly within asm blocks. Strings are concatenated automatically.
Prevent the compiler from optimizing away assembly that has side effects.
Zen C simplifies the complex GCC constraint syntax with named bindings.
| Type | Syntax | GCC Equivalent |
|---|---|---|
| Output | : out(variable) | "=r"(variable) |
| Input | : in(variable) | "r"(variable) |
| Clobber | : clobber("rax") | "rax" |
| Memory | : clobber("memory") | "memory" |
Note: When using Intel syntax (via
-masm=intel), you must ensure your build is configured correctly (for example,//> cflags: -masm=intel). TCC does not support Intel syntax assembly.
Zen C supports special comments at the top of your source file to configure the build process without needing a complex build system or Makefile.
| Directive | Arguments | Description |
|---|---|---|
//> link: | -lfoo or path/to/lib.a | Link against a library or object file. |
//> lib: | path/to/libs | Add a library search path (-L). |
//> include: | path/to/headers | Add an include search path (-I). |
//> framework: | Cocoa | Link against a macOS framework. |
//> cflags: | -Wall -O3 | Pass arbitrary flags to the C compiler. |
//> define: | MACRO or KEY=VAL | Define a preprocessor macro (-D). |
//> pkg-config: | gtk+-3.0 | Run pkg-config and append --cflags and --libs. |
//> shell: | command | Execute a shell command during the build. |
//> get: | http://url/file | Download a file if specific file does not exist. |
1. OS Guarding Prefix directives with an OS name to apply them only on specific platforms. Supported prefixes: linux:, windows:, macos: (or darwin:).
2. Environment Variable Expansion Use ${VAR} syntax to expand environment variables in your directives.
The following keywords are reserved in Zen C.
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
The following identifiers are reserved because they are keywords in 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 offers two ways to interact with C code: Trusted Imports (Convenient) and Explicit FFI (Safe/Precise).
You can import a C header directly using the import keyword with the .h extension. This treats the header as a module and assumes all symbols accessed through it exist.
Pros: Zero boilerplate. Access everything in the header immediately. Cons: No type safety from Zen C (errors caught by C compiler later).
For strict type checking or when you don't want to include the text of a header, use extern fn.
Pros: Zen C ensures types match. Cons: Requires manual declaration of functions.
import "file.h"**: Registers the header as a named module. Enables implicit access to symbols (for example, file::function()).include <file.h>**: Purely emits #include <file.h> in the generated C code. Does not introduce any symbols to the Zen C compiler; you must use extern fn to access them.Zen C includes a standard library (std) covering essential functionality.
Browse the Standard Library Documentation
| Module | Description | 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.zc** | TCP networking (Sockets). | 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 |
Zen C provides a built-in Language Server and REPL to enhance the development experience.
The Zen C Language Server (LSP) supports standard LSP features for editor integration, providing:
To start the language server (typically configured in your editor's LSP settings):
It communicates via standard I/O (JSON-RPC 2.0).
The Read-Eval-Print Loop allows you to experiment with Zen C code interactively.
~/.zprep_history.~/.zprep_init.zc.| Command | Description |
|---|---|
:help | Show available commands. |
:reset | Clear current session history (variables/functions). |
:vars | Show active variables. |
:funcs | Show user-defined functions. |
:structs | Show user-defined structs. |
:imports | Show active imports. |
:history | Show session input history. |
:type <expr> | Show the type of an expression. |
:c <stmt> | Show the generated C code for a statement. |
:time <expr> | Benchmark an expression (runs 1000 iterations). |
:edit [n] | Edit command n (default: last) in $EDITOR. |
:save <file> | Save the current session to a .zc file. |
:load <file> | Load and execute a .zc file into the session. |
:watch <expr> | Watch an expression (re-evaluated after every entry). |
:unwatch <n> | Remove a watch. |
:undo | Remove the last command from the session. |
:delete <n> | Remove command at index n. |
:clear | Clear the screen. |
:quit | Exit the REPL. |
! <cmd> | Run a shell command (e.g. !ls). |
Zen C is designed to work with most C11 compilers. Some features rely on GNU C extensions, but these often work in other compilers. Use the --cc flag to switch backends.
| Compiler | Pass Rate | Supported Features | Known Limitations |
|---|---|---|---|
| GCC | 100% | All Features | None. |
| Clang | 100% | All Features | None. |
| Zig | 100% | All Features | None. Uses zig cc as a drop-in C compiler. |
| TCC | **~70%** | Basic Syntax, Generics, Traits | No __auto_type, No Intel ASM, No Nested Functions. |
Recommendation: Use GCC, Clang, or Zig for production builds. TCC is excellent for rapid prototyping due to its compilation speed but misses some advanced C extensions Zen C relies on for full feature support.
Zig's zig cc command provides a drop-in replacement for GCC/Clang with excellent cross-compilation support. To use Zig:
Zen C can generate C++-compatible code with the --cpp flag, allowing seamless integration with C++ libraries.
Include C++ headers and use raw blocks for C++ code:
Note: The
--cppflag switches the backend tog++and emits C++-compatible code (usesautoinstead of__auto_type, function overloads instead of_Generic, and explicit casts forvoid*).
Zen C supports GPU programming by transpiling to CUDA C++. This allows you to leverage powerful C++ features (templates, constexpr) within your kernels while maintaining Zen C's ergonomic syntax.
| Attribute | CUDA Equivalent | Description |
|---|---|---|
@global | __global__ | Kernel function (runs on GPU, called from host) |
@device | __device__ | Device function (runs on GPU, called from GPU) |
@host | __host__ | Host function (explicit CPU-only) |
Zen C provides a clean launch statement for invoking CUDA kernels:
This transpiles to: kernel_name<<<grid, block, shared, stream>>>(args);
Use Zen C function syntax with @global and the launch statement:
Zen C provides a standard library for common CUDA operations to reduce raw blocks:
Note: The
--cudaflag setsnvccas the compiler and implies--cppmode. Requires the NVIDIA CUDA Toolkit.
Zen C supports modern C23 features when using a compatible backend compiler (GCC 14+, Clang 14+, TCC (partial)).
auto**: Zen C automatically maps type inference to standard C23 auto if __STDC_VERSION__ >= 202300L._BitInt(N)**: Use iN and uN types (e.g., i256, u12, i24) to access C23 arbitrary-width integers.Zen C can compile to Objective-C (.m) using the --objc flag, allowing you to use Objective-C frameworks (like Cocoa/Foundation) and syntax.
Use include for headers and raw blocks for Objective-C syntax (@interface, [...], @"").
Note: Zen C string interpolation works with Objective-C objects (
id) by callingdebugDescriptionordescription.
We welcome contributions! Whether it's fixing bugs, adding documentation, or proposing new features.
git checkout -b feature/NewThing.make test.tests/.The test suite is your best friend.
src/parser/ - Recursive descent parser.src/codegen/ - Transpiler logic (Zen C -> GNU C/C11).std/ - Written in Zen C itself.This project uses third-party libraries. Full license texts can be found in the LICENSES/ directory.