The SafeC programming language
Safe, deterministic systems programming
SafeC is C, evolved: compile-time memory safety through regions, no garbage collector and no hidden runtime, while keeping C's ABI, its headers and its toolchain. Write kernels, audio engines, servers, GUIs and WebAssembly in one language you can read like C.
extern int printf(const char* fmt, ...);
region Frame { capacity: 4096 }
struct Particle { float x; float v; };
// The region is part of the type: p can't outlive the arena.
void step(&arena<Frame> Particle p, float dt) {
p.x = p.x + p.v * dt;
}
int main() {
&arena<Frame> Particle p = new<Frame> Particle;
p.x = 0.0;
p.v = 2.5;
for (int i = 0; i < 3; i = i + 1) {
step(p, 0.5);
printf("t=%d x=%.2f\n", i, p.x);
}
arena_reset<Frame>(); // O(1): no per-object free, no GC
return 0;
}
Run in PlaygroundWhy SafeC
Keep everything that makes C the language of systems — predictable performance, a stable ABI, every platform — and let the compiler reject the bugs C lets through.
Memory safety without a GC
Every reference carries its region — stack, heap, arena<R> or static — and the compiler proves it can't dangle, alias mutably or escape. No collector, no reference counts, no runtime metadata.
Speaks C natively
C struct layout, C calling conventions and C symbol names by default. #include <stdio.h> works; link SafeC objects into any C or C++ project and call C libraries without bindings.
Deterministic by design
No implicit allocations, no exceptions, no hidden copies, no narrowing conversions. The same input gives the same output with costs you can see — what real-time audio and control loops need.
Bare metal and WebAssembly
--freestanding builds for 15 no-OS targets (Cortex-M, RISC-V, x86, AArch64) with interrupt handlers, inline assembly and volatile MMIO. --target=wasm32 builds browser modules with std/wasm DOM bindings.
Async without a runtime tax
std/async brings Rust-style futures and wakers as a library: stackless state machines, a no-heap single-threaded executor that runs on bare metal and wasm, a thread pool, timers and async TCP.
A standard library for real programs
30+ generic, void*-free modules: collections, a web stack (HTTP server, router, WebSocket, gzip), a GUI toolkit, real-time audio and MIDI, ML tensors on CPU and GPU, crypto, serialization.
Bugs C compiles, SafeC rejects
Each pair below is the same mistake. The C version builds without complaint and fails at run time — maybe. The SafeC version doesn't build, and the compiler says why.
C — compiles, returns a dangling pointer
int* counter() {
int x = 42;
return &x; // warning at best; UB when used
}
SafeC — compile-time error
&stack int counter() {
int x = 42;
return &x;
}
error: cannot return '&stack int': stack reference escapes function scope
C — a null pointer is just a pointer
struct Node { int value; };
int read(struct Node* n) {
return n->value; // crashes when n == NULL
}
SafeC — nullable references must be checked
struct Node { int value; };
int read(?&Node n) {
return n.value;
}
error: dereference of nullable reference '?&Node' requires 'unsafe', or use match/is_null()/.default(value) instead
C — silent truncation
long big = 5000000000L;
int small = big; // implementation-defined result
SafeC — narrowing is explicit
long big = 5000000000L;
int small = big;
error: type mismatch in variable declaration: cannot convert 'long' to 'int'
Batteries included
The standard library is written in SafeC, links only the modules a program uses, and ships prebuilt for every release platform.
Web server
#include <std/http/router.h>
struct HttpResponse hello(&HttpRequest req, &HttpCtx ctx) {
struct String body = std::String::from("Hello, ");
body.push(ctx.param_or("name", "world"));
struct HttpResponse r = std::HttpResponse::text(200, body.as_ptr());
body.free();
return r;
}
int main() {
struct Router app = std::Router::new();
defer app.drop();
app.use_logger();
app.use_gzip(1024UL);
app.get("/hello/:name", hello);
app.static_dir("/assets", "./public");
struct HttpServerConfig cfg = std::HttpServerConfig::defaults(8080);
return app.listen(&cfg); // keep-alive HTTP/1.1 on the I/O reactor
}
Router, middleware, HTTPS, static files, cookies, multipart, SSE, WebSocket and a redirect-following client with gzip — HTTP & Web.
GUI
#include <std/gui/gui_app.h>
static void on_click(&Widget w, ?&Widget label) {
match (label) { case some(l): { l.set_text("Clicked!"); } case null: { } }
}
int main() {
struct GuiApp app = GuiApp::new();
?&GuiWindow ow = app.open_window("Hello", 360, 200);
match (ow) {
case null: { app.free(); return 1; } // no display
case some(win): {
&Widget root = Widget::vstack().set_padding(16);
&Widget label = Widget::label("Hello from SafeC");
root.add_child(label);
root.add_child(Widget::button("Click me").on_click(on_click, label));
app.set_root(win, root);
app.run(); // until the window closes
}
}
app.free();
return 0;
}
An anti-aliased vector canvas with TrueType text and 30+ themed widgets on X11, Wayland, Win32, Cocoa and the web (WebAssembly) — GUI.
Async
#include <std/async/async.h>
#include <std/async/host.h>
extern int printf(const char* fmt, ...);
struct Countdown {
int st; int i; struct Sleep d;
struct Poll<int> poll(&Context cx);
void drop();
};
struct Poll<int> Countdown::poll(&Context cx) {
ASYNC_BEGIN(self.st, 1); // one await point
for (self.i = 3; self.i > 0; self.i = self.i - 1) {
self.d = Sleep::new(100LL);
AWAIT(1, self.d); // Pending until the timer fires
printf("%d\n", self.i);
}
ASYNC_RETURN(42);
ASYNC_END;
}
void Countdown::drop() { if (self.st == 1) self.d.drop(); }
int main() {
struct Countdown c; c.st = ASYNC_INIT;
int v = block_on(&c); // or LocalExecutor / ThreadPool / Runtime
c.drop();
return v == 42 ? 0 : 1;
}
Futures, wakers, join/select/timeout, channels and async TCP over epoll, kqueue and WSAPoll — Async. (The ASYNC_* coroutine macros need compat_preprocessor = true.)
Audio
#include <std/audio/audio.h>
#include <std/math.h>
struct Tone { double phase; double step; };
// The real-time callback: fill the output buffer, never allocate or block.
int render(&AudioIo io, ?&Tone tp) {
match (tp) {
case some(t): {
[]float out = io.output_f32(); // frames x channels, interleaved
for (unsigned int f = 0U; f < io.frames; f = f + 1U) {
float v = (float)(0.2 * std::sin_d(t.phase));
out[(unsigned long)f * 2UL] = v; // bounds-checked
out[(unsigned long)f * 2UL + 1UL] = v;
t.phase = t.phase + t.step;
}
}
case null: {}
}
return AUDIO_CB_CONTINUE;
}
Real-time audio and MIDI on ALSA, JACK, Core Audio, WASAPI and Web Audio — Audio & MIDI.
Bare metal & wasm
#define LED_PORT ((unsigned int*)0x40020014)
// safec --target=arm-7em --freestanding blink.sc
interrupt void systick_handler() {
unsafe { volatile_store(LED_PORT, volatile_load(LED_PORT) ^ 1U); }
}
// safec --target=wasm32 fib.sc -> a module exporting fib()
__attribute__((export_name("fib")))
int fib(int n) { return n < 2 ? n : fib(n - 1) + fib(n - 2); }
The whole standard library builds for every bare-metal target; std/wasm drives the DOM from SafeC — Bare-Metal, WebAssembly & DOM.
Machine learning, CPU to GPU
std/ml trains and runs neural networks in SafeC itself — tensors with autograd, the layers today's models are built from, and GPU backends — with no Python and no framework runtime.
- Tensors and autograd.
DenseTensor<E>with reverse-mode autograd, stored as float32 (FloatTensor), fp16 (HalfTensor) or bf16 (BF16Tensor) and computed in float32. - Layers and models. MLPs, losses and optimizers from SGD to AdamW and Lion; multi-head, flash and advanced attention (MLA, Gated DeltaNet); DiT and JiT transformers, RNNs and xLSTM, Mamba, CNNs and ResNet-style ConvNets, U-Net and diffusion, autoencoders, GANs, reinforcement learning and LoRA / QLoRA fine-tuning.
- One kernel set, every GPU. The same training code runs on the CPU (built-in GEMM or a vendor BLAS) or on a tensor device: CUDA, ROCm, Metal, Vulkan (SPIR-V) or WebGPU, all from one kernel source, with fp16 and bf16 mixed precision.
- Measured. Against PyTorch's best configuration, SafeC trains a small MLP 2.6× (MI100) and 7.8× (H200) faster and decodes Gemma 4 E2B 3.1× and 1.5× faster; on an M1 Pro, MLX and PyTorch still win some tests. See the benchmarks.
#include <std/ml/module.h>
#include <std/ml/datasets.h>
#include <std/ml/trainer.h>
extern int printf(const char* fmt, ...);
// The forward pass builds the autograd graph as it goes.
static &FloatTensor clf_loss(&Mlp m, const &FloatTensor x,
const &FloatTensor y) {
return tensor_cross_entropy_loss(m.forward(x), y);
}
static &FloatTensor clf_logits(&Mlp m, const &FloatTensor x) {
return m.forward(x);
}
int main() {
struct Rng rng = Rng::new(1UL);
struct Dataset data = Dataset::moons(400UL, 0.1f, &rng);
defer data.drop();
struct DatasetSplit sp = data.split(0.25f, &rng);
defer sp.train.drop();
defer sp.test.drop();
struct Mlp net = Mlp::new(2UL, 32UL, 2UL, 2UL, ACT_RELU, ACT_NONE, &rng);
defer net.drop();
struct Optimizer opt = Optimizer::new(OPT_ADAM, 0.01f);
defer opt.drop();
model_add_params(&net, &opt);
struct TrainConfig cfg = TrainConfig::default();
cfg.epochs = 60UL;
cfg.device = device_auto(); // a GPU if built in, else the CPU
trainer_fit(&net, clf_loss, &opt, &sp.train, &cfg);
float acc = trainer_accuracy(&net, clf_logits, &sp.test, 64UL);
printf("accuracy %.2f on %s\n", acc, device_name(cfg.device));
return 0;
}
Install
macOS & Linux
curl -fsSL https://raw.githubusercontent.com/safec-org/SafeC/main/install.sh | bash
Windows
irm https://raw.githubusercontent.com/safec-org/SafeC/main/install.ps1 | iex
Then create a project and run it:
safeguard new hello && cd hello
safeguard run
SafeC needs clang 21 or newer to compile and link (the installer finds it or tells you how to get it). See Install for options, requirements and building from source.
Get going
Learn
The Book, the guide, the language reference and the standard library, in one place.
Playground
Edit and run SafeC in your browser, load the Book's examples and share a program as a link.
Tools
safeguard builds, tests, formats and lints; sc-lsp brings diagnostics and completion to your editor.
Community
Report bugs, propose features and send pull requests on GitHub.
GitHub
The compiler, the standard library, safeguard and the install scripts — MIT licensed.