Introduction to SafeC
SafeC is a deterministic, region-aware, compile-time-first systems programming language. It is an evolution of C that preserves full C ABI compatibility while enforcing memory safety, type safety, and real-time determinism — all at compile time, with zero runtime overhead.
Why SafeC?
C remains the foundation of systems programming: operating systems, embedded firmware, audio engines, network stacks. But C's lack of memory safety is a persistent source of bugs, vulnerabilities, and undefined behavior.
Existing alternatives each demand significant trade-offs:
- C++ adds safety features but also adds hidden costs: implicit constructors, destructors, exceptions, RTTI, vtables.
- Rust provides strong safety guarantees but requires learning an entirely new ownership model, a new ecosystem, and non-trivial FFI to interface with C.
- Zig removes hidden behavior but uses a fundamentally different memory model based on allocators rather than regions.
SafeC takes a different approach: start from C and add safety, without adding hidden cost.
extern int printf(const char* fmt, ...);
int main() {
int x = 42;
&stack int ref = &x; // explicit region annotation
printf("x = %d\n", *ref);
return 0;
}
Run in PlaygroundIf you know C, you already know most of SafeC. The additions are explicit, visible, and predictable.
Core Identity
SafeC is defined by five non-negotiable principles:
1. Determinism
The same input always produces the same output. No hidden runtime variance, no non-deterministic behavior. This makes SafeC suitable for real-time systems, audio processing, embedded firmware, and any domain where predictability is not optional.
2. Zero Hidden Cost
Every operation has a visible, predictable cost. There are no implicit heap allocations, no implicit copies, no background garbage collection, no implicit destructor chains. What you write is what executes.
3. Explicit Control
No implicit memory management, no implicit type conversions, no implicit error handling. The programmer controls allocation, lifetime, and error propagation explicitly. The compiler verifies correctness.
4. C ABI Compatibility
SafeC uses C struct layout, C calling conventions, and C linkage by default. SafeC objects link directly into C projects. C headers can be included natively with #include <stdio.h>.
5. Compile-Time-First Design
Anything knowable at compile time is resolved at compile time. consteval functions execute during compilation. static_assert catches errors before any code runs. if const selects branches at compile time. Generics are monomorphized — no runtime dispatch.
The Determinism Contract
SafeC guarantees the absence of hidden runtime behavior:
- No hidden heap allocation — all allocation is explicit (
new<R>,malloc) - No hidden runtime — no runtime library required (freestanding mode available)
- No hidden panics — the only run-time traps are the bounds and range checks on dynamic indexing and slicing (left out inside
unsafe { }) - No implicit exceptions — errors are returned, not thrown
- No background GC — memory is managed through regions and explicit deallocation
- No implicit destructor calls — resource cleanup is explicit (
defer, manual free)
What SafeC Adds to C
SafeC extends C with safety and modern features while preserving C's execution model:
| Feature | Description |
|---|---|
| Regions | &stack T, &heap T, &arena<R> T, &static T, or &T/?&T (no region at all) — compile-time memory safety |
| Bounds checking | Static and runtime array bounds verification |
| Borrow checking | Mutable/immutable reference exclusion enforced at compile time |
| Generics | generic<T> with monomorphization — zero runtime cost |
| Struct methods | Point::length() syntax with implicit self receiver |
| Operator overloading | Vec2 operator+(Vec2 other) const |
| Pattern matching | match expressions with exhaustiveness checking |
| Optional types | ?T (implicit T -> ?T wrap), unwrapped via match, .is_null()/.is_none(), or .default(fallback) |
| Slices | []int s = arr[0..3] — bounds-checked views into arrays |
| Defer | defer close(fd) — deterministic cleanup |
| Compile-time evaluation | consteval, static_assert, if const |
| Tuples | tuple(int, double) with .0, .1 member access |
| Ownership | Types with drop() must be dropped or moved exactly once on every path — checked at compile time, never called for you |
| Concurrency | spawn/join/spawn_scoped, channels, compile-time Send/Sync checks |
| Bare-metal support | naked, interrupt, asm, --freestanding |
What SafeC Does NOT Add
Equally important is what SafeC deliberately omits:
- No garbage collector
- No exceptions
- No RTTI or virtual dispatch
- No implicit constructors or destructors
- No hidden allocations
- No standard runtime requirement
- No class hierarchies or inheritance
Project Components
The SafeC project consists of these components:
Compiler (safec) — A full LLVM frontend that compiles .sc files to LLVM IR. The pipeline is: Preprocessor, Lexer, Parser, AST, Sema (semantic analysis), ConstEval (compile-time evaluation), CodeGen (LLVM IR generation).
Standard Library (std/) — about 300 headers in 27 sections: memory, I/O, strings, math, collections and allocators; threads, synchronization and async; networking, TLS, HTTP and the web; GUI, audio and DSP; machine learning; crypto, encoding, serialization and file systems; SIMD, HAL and bare-metal kernels — see the Standard Library. All implemented in SafeC, with C FFI for system calls.
Package Manager (safeguard) — A build tool and dependency manager. Handles compilation, linking, dependency fetching, tests, formatting, linting, app bundles, API docs and standard library integration.
Language server (sc-lsp) — Editor support built on the compiler's own frontend (see Tools).
Self-hosted compiler (scc) — A SafeC compiler written in SafeC, built to WebAssembly for the Playground.
File Extension
SafeC source files use the .sc extension:
hello.sc
math_utils.sc
audio_engine.sc
Next Steps
- Getting Started — Install the compiler and write your first program
- Design Philosophy — Understand the principles behind SafeC's decisions
- Comparison — See how SafeC compares to C, C++, Rust, and Zig