# Appendix F. C Interop Reference

### Appendix F. C Interop Reference

One of Zig's central goals is direct interoperability with C. Zig can call C code, compile C code, link system libraries, export functions to C, and translate C headers.

This appendix gives the common forms.

### F.1 Calling a C Function

A C function declaration uses `extern`.

```zig
extern fn puts(s: [*:0]const u8) c_int;
```

Use it like an ordinary Zig function.

```zig
pub fn main() void {
    _ = puts("hello from c");
}
```

`c_int` is the Zig type matching C `int`.

### F.2 `@cImport`

Most C libraries are imported with `@cImport`.

```zig
const c = @cImport({
    @cInclude("stdio.h");
});
```

Use C declarations through the namespace.

```zig
pub fn main() void {
    _ = c.printf("value = %d\n", 123);
}
```

### F.3 Importing Multiple Headers

```zig
const c = @cImport({
    @cInclude("stdio.h");
    @cInclude("stdlib.h");
    @cInclude("string.h");
});
```

### F.4 Defining C Macros

```zig
const c = @cImport({
    @cDefine("VALUE", "123");
    @cInclude("config.h");
});
```

Remove a macro:

```zig
const c = @cImport({
    @cUndef("min");
    @cInclude("windows.h");
});
```

### F.5 Zig and C Integer Types

C compatibility types:

```zig
c_char
c_short
c_ushort
c_int
c_uint
c_long
c_ulong
c_longlong
c_ulonglong
```

Floating-point:

```zig
c_float
c_double
c_longdouble
```

These follow the target C ABI.

### F.6 C Strings

A C string is usually:

```zig
[*:0]const u8
```

Meaning:

- many-item pointer
- terminated by zero
- immutable bytes

Example:

```zig
extern fn puts(s: [*:0]const u8) c_int;
```

A Zig string literal can be passed directly.

```zig
_ = puts("hello");
```

### F.7 C Pointers

C pointer:

```zig
int *
```

Usually becomes:

```zig
[*c]c_int
```

This is a special C pointer type.

Example:

```zig
extern fn strlen(s: [*:0]const u8) usize;
```

Nullable pointer:

```zig
?*T
```

### F.8 Struct Layout

Use `extern struct` for C ABI layout.

```zig
const Point = extern struct {
    x: c_int,
    y: c_int,
};
```

Without `extern`, Zig may choose a different layout.

### F.9 Packed Layout

Use `packed struct` for exact bit layout.

```zig
const Flags = packed struct {
    a: bool,
    b: bool,
    c: u6,
};
```

Packed layout is for protocols, devices, binary formats, and hardware registers.

### F.10 Linking libc

Link the system C library:

```zig
exe.linkLibC();
```

Many POSIX APIs require this.

### F.11 Linking a System Library

```zig
exe.linkSystemLibrary("m");
```

Examples:

```zig
exe.linkSystemLibrary("SDL2");
exe.linkSystemLibrary("sqlite3");
exe.linkSystemLibrary("ssl");
```

### F.12 Compiling C Source Files

```zig
exe.addCSourceFile(.{
    .file = b.path("src/add.c"),
    .flags = &.{ "-std=c99" },
});
```

Multiple files:

```zig
exe.addCSourceFiles(.{
    .root = b.path("csrc"),
    .files = &.{
        "a.c",
        "b.c",
    },
});
```

### F.13 Include Paths

```zig
exe.addIncludePath(b.path("include"));
```

System include path:

```zig
exe.addSystemIncludePath(.{
    .cwd_relative = "/usr/include",
});
```

### F.14 Exporting Zig Functions

Expose a Zig function to C:

```zig
export fn add(a: c_int, b: c_int) c_int {
    return a + b;
}
```

Compile as a shared library or static library.

### F.15 Calling Convention

Specify a calling convention:

```zig
fn callback() callconv(.c) void {}
```

Most C APIs use `.c`.

### F.16 Opaque Types

Opaque types are useful for C handles.

```zig
const SDL_Window = opaque {};
```

A pointer may exist:

```zig
var window: *SDL_Window = undefined;
```

But the contents are unknown to Zig.

### F.17 Translating Headers

Translate a C header:

```sh
zig translate-c header.h
```

This produces Zig declarations from the C source.

The output is often useful as a reference even if it is not checked into a project.

### F.18 Memory Ownership

C APIs often allocate memory.

Example pattern:

```zig
const p = c.malloc(1024);
defer c.free(p);
```

Ownership rules must be explicit:

- who allocates
- who frees
- which allocator is used
- whether null is possible

Do not hide ownership behind wrappers unless the wrapper improves correctness.

### F.19 Error Handling

C often signals failure with:

```text
NULL
-1
0
errno
```

Wrap these immediately.

```zig
fn openFile() !File {
    const fd = c.open(...);

    if (fd < 0) {
        return error.OpenFailed;
    }

    return File{ .fd = fd };
}
```

Translate weak C conventions into Zig errors near the boundary.

### F.20 Volatile Memory

Memory-mapped hardware often requires `volatile`.

```zig
const reg: *volatile u32 = @ptrFromInt(0x40000000);
```

Ordinary memory should not use volatile.

### F.21 Inline Assembly

Zig supports inline assembly.

```zig
asm volatile ("nop");
```

Output and input operands:

```zig
asm volatile (
    "add %[b], %[a]"
    : [a] "=r" (result)
    : [b] "r" (value),
);
```

Assembly is target-specific. Keep it isolated and documented.

### F.22 A Small Example

C source:

```c
int add(int a, int b) {
    return a + b;
}
```

Build script:

```zig
exe.addCSourceFile(.{
    .file = b.path("src/add.c"),
});
```

Zig source:

```zig
extern fn add(a: c_int, b: c_int) c_int;

const std = @import("std");

pub fn main() void {
    const n = add(10, 20);

    std.debug.print("{d}\n", .{n});
}
```

This is the ordinary model for Zig and C:

- declare external symbols
- compile or link C code
- use C APIs directly
- convert weak interfaces into explicit Zig types at the boundary

