01
Predictable by design
Left-to-right evaluation, automatic reference counting, and block-scoped defer make ownership and cleanup explicit.
Draft 0.50 experimental systems language
C~ brings C#-style structure to native systems work. It compiles to deterministic C23 for desktop programs, freestanding images, Cosmopolitan executables, ESP-IDF firmware, and trusted managed applications on ESP32—without the CLR.
01
Left-to-right evaluation, automatic reference counting, and block-scoped defer make ownership and cleanup explicit.
02
Deterministic C23 output, native imports, exported C ABI functions, inline assembly, and runtime-effect contracts keep every boundary visible.
03
Use the same language and standard-library surface for hosted programs, ESP-IDF firmware, controlled GNU/ELF freestanding images, and x86-64 Cosmopolitan APEs.
Current implementation
C~ keeps target choices explicit. Hosted applications can lean on native libraries and profile-guided optimization; firmware and freestanding programs provide the services their standard library needs; ESP32 can also load trusted C~ applications at runtime.
Standard library
Strings and strict UTF-8, incremental line reading, stable merge sorting, files, collections, math, geometry, time, random numbers, threads, mutexes, and TLS ship as source with the compiler.
Native performance
Select size, speed, or aggressive optimization, baseline or AVX2 code generation, precise or fast floating point, LTO, and hosted PGO without hiding the resolved native flags.
/O1 and -Os size profilesHosted
Build Windows and Linux executables, load allowlisted native libraries, and use the full synchronous I/O and threading surface. The HostedIo example combines a 12-worker packet renderer with a flattened SAH BVH.
ESP-IDF storage
Draft 0.46 adds block devices, primary MBR partitions, explicit FAT formatting and mounts, T-CAN485 SDSPI support, and generation-aware removable-media handling.
Managed ESP32 apps
Managed Module ABI 3 packages checked resident ELFs with optional Xtensa code overlays. Schema-3 references compile without provider source, and Runtime ABI 22 keeps managed calls cleanup-safe across returns and exceptions.
Tooling
VS Code and Visual Studio share project-aware language services. Source-file changes refresh project membership while unchanged syntax trees are reused. Native debugging maps execution back to C~ source.
Managed modules are ESP-IDF-only trusted native code. Checked cross-module calls now work; canonical descriptor substitution, shared generic implementations, and complete cross-module exception and resource handling remain in development.
A taste of C~
Some panels show excerpts. Follow each example link for the complete program and target setup.
01 / INTRO
C~ keeps familiar C#-style structure while producing a native program through its GNU C23 backend.
View the complete exampleusing System;
namespace Examples;
public static class Program
{
[EntryPoint]
public static void Main()
{
uint left = 2u;
uint right = 3u;
uint result = left + right;
Console.WriteLine(result);
}
}
02 / OBJECTS
Classes support constructors, single inheritance, virtual members, overrides, properties, delegates, and explicit casts.
Explore the object modelpublic class Base
{
protected int number;
public Base(int number)
{
this.number = number;
}
public virtual int Read()
{
return number;
}
}
public class Derived : Base
{
public Derived() : base(4) { }
public override int Read()
{
return base.Read() + 1;
}
}
03 / DEFER
A deferred call captures its arguments immediately and runs on every ordinary exit from the surrounding block, in LIFO order.
See deterministic cleanupusing System;
using System.IO;
public static class Program
{
[EntryPoint]
public static void Main()
{
FileHandle image = File.Open(
"image.ppm",
FileMode.Create,
FileAccess.Write);
defer File.Close(image);
Console.WriteLine("Rendering...");
}
}
04 / NATIVE
Attributes describe exact external symbols, transitive effect contracts, exported entry points, and interrupt-safe native boundaries instead of hiding semantic or ABI boundaries.
Browse native featurespublic static class NativeInterop
{
[Extern("ct_native_utf8_length")]
[NoAlloc]
[NoThrow]
[NoBlock]
public static uint Utf8Length(
NativeUtf8String value);
}
public static class Program
{
[Interrupt]
[Export("timer_isr")]
public static unsafe void TimerIsr(void* context)
{
// Compiler-checked runtime-free IRAM closure.
}
[Export("ctilde_add")]
[NoRuntime]
[NoBlock]
public static int Add(int left, int right)
{
return left + right;
}
}
05 / GENERICS
Types and methods support type parameters and integral constant parameters. Reachable closed forms are monomorphized.
Read about genericspublic class Box<T>
{
public T Value;
}
public static T Identity<T>(T value)
{
return value;
}
public struct Buffer<T, const int Capacity>
{
public T[Capacity] Items;
}
Box<int> box = new Box<int>();
Buffer<byte, 64> buffer;
06 / EXCEPTIONS
Typed catches, catch-all handlers, rethrow, and finally provide structured failure handling and cleanup.
try
{
Work();
}
catch (SpecificException error)
{
Console.WriteLine(error.Message);
}
catch (Exception)
{
throw;
}
catch
{
Console.WriteLine("fallback");
}
finally
{
Console.WriteLine("cleanup");
}
07 / UNSAFE
Unsafe blocks expose pointers, address operations, stack allocation, and unmanaged calls while preserving static type checking.
Read about unsafe codepublic static unsafe void Clear(
byte* address,
int length)
{
for (int index = 0; index < length; index++)
{
address[index] = 0;
}
}
unsafe
{
NativeBuffer<byte> data =
stackalloc byte[128];
data[0] = 42;
}
08 / ASSEMBLY
GNU assembly uses declared input, output, read/write, constraint, and clobber clauses instead of implicit native state.
Read about inline assembly[NoAlloc]
asm (
in value as source,
out("&r") result,
ref accumulator,
clobber("eax", "cc", "memory")
) {
movl source, %eax
addl %eax, accumulator
movl %eax, result
}
09 / ASSEMBLY FUNCTIONS
Raw GNU assembly functions have a typed C ABI boundary. Parameters and results use explicit operands while effect attributes describe the opaque native work.
Read about assembly functions[NoRuntime]
[NoBlock]
public static unsafe asm void DebugWrite(char value)
(in("a") value as output)
{
outb output, $0xe9
}
[NoRuntime]
[NoBlock]
public static unsafe asm uint ReadPort()
(out("a") result as value)
{
inl $0xf4, value
}
DebugWrite('C');
uint status = ReadPort();
10 / CONSTANT IMAGE DATA
[ConstInit] evaluates restricted unmanaged values at compile time and emits immutable storage directly into the native image—without a module initializer or runtime edge.
[Packed(4)]
public readonly struct MultibootHeader
{
public readonly uint Magic;
public readonly uint Flags;
public readonly uint Checksum;
public MultibootHeader(uint magic, uint flags, uint checksum)
{
Magic = magic;
Flags = flags;
Checksum = checksum;
}
}
[ConstInit]
[Used]
[Section(".multiboot")]
[Align(4)]
private static readonly MultibootHeader Header =
new MultibootHeader(
0x1BADB002u,
0x00000003u,
0u - 0x1BADB002u - 0x00000003u);
static assert(sizeof(MultibootHeader) == 12u);
11 / FREESTANDING QEMU
The QEMU example combines immutable Multiboot data, assembly functions, a naked C~ entry point, explicit runtime lifecycle calls, and a regular string—without libc, a CRT, or a source assembly file.
Boot the complete kernel[Export("kernel_main")]
[NoAlloc]
[NoBlock]
public static unsafe int Main()
{
Write("CTILDE_QEMU_OK\n");
return 0;
}
[Naked]
[Export("_start")]
[NoAlloc]
public static unsafe asm void Start()
{
cli
cld
movl $stack_top, %esp
xorl %ebp, %ebp
call ct_runtime_initialize
call kernel_main
movl %eax, %ebx
call ct_runtime_shutdown
movl %ebx, %eax
outl %eax, $0xf4
1:
hlt
jmp 1b
}
12 / COLLECTIONS
Generic lists, stacks, queues, sets, dictionaries, and fail-fast enumerators are part of the C~ standard library.
Run the collections tourusing System.Collections;
List<int> values = new List<int>();
values.Add(2);
values.Insert(0, 1);
ListEnumerator<int> items = values.GetEnumerator();
while (items.MoveNext())
Console.WriteLine(items.Current);
13 / SIMD128
F32x4, integer lanes, masks, and Vec3x4 have fixed 16-byte semantics with portable scalar lowering and explicit supported-target SIMD128 lowering.
F32x4 a = rays.Directions.LengthSquared();
F32x4 halfB = centerToOrigin.Dot(rays.Directions);
F32x4 c = centerToOrigin.LengthSquared()
- F32x4.Splat(radius * radius);
F32x4 discriminant = halfB * halfB - a * c;
Mask32x4 hits = F32x4.CompareGreaterThanOrEqual(
discriminant, F32x4.Zero);
14 / REMOVABLE STORAGE
The ESP-IDF storage layer exposes block devices, primary MBR layouts, FAT volumes, and a generation-aware removable-SD monitor.
Read the storage contractusing Esp.Idf.Storage;
RemovableSdCardMonitor card =
new RemovableSdCardMonitor(
SdSpiConfiguration.TCan485);
card.AddFatMount(0, "/sd", 8);
card.Start();
if (card.State == RemovableStorageState.Faulted)
card.Remount();
15 / MANAGED ESP32 APPLICATION
A .ctm application shares Runtime ABI 22 with firmware while keeping mutable statics, heap accounting, cancellation, copied mailboxes, console endpoints, child tasks, and an executable overlay window process-local. Draft 0.50 separates executable code from loader metadata and data, infers private helper placement, and gates the final executable working set. ManagedShell uses the same shell.ctm for UART, SSH, and one-command sessions; its development SSH modules add encrypted public-key channels and rooted SFTP without placing protocol code in firmware.
using System.Diagnostics;
using System.Text;
[EntryPoint]
public static int Main(string[] args)
{
Process current = Process.Current;
byte[] payload;
if (current.TryReceive(250u, out payload))
Console.WriteLine(Encoding.UTF8.GetString(payload));
if (Process.IsCancellationRequested)
return -1;
return 0;
}
16 / RUNTIME PROVIDERS
Freestanding and ESP-IDF projects can satisfy typed runtime roles for allocation, panic, console, files, clocks, threads, mutexes, and TLS.
Inspect a freestanding provider[RuntimeImpl(Runtime.ConsoleWrite)]
[NoAlloc]
[NoThrow]
[NoBlock]
[NoRuntime]
private static unsafe RuntimeTransferResult ConsoleWrite(
ReadOnlyNativeBuffer<byte> value)
{
// Platform-specific output.
return new RuntimeTransferResult(
RuntimeStatus.Success, 0, value.Length);
}
Open source