# Calling C

> Declare C functions with lib and fun, pass UTF-8 strings and arrays, read out-parameters, hand C a callback written as a lambda, and keep pointers inside unsafe blocks.

Canonical: https://alice-lang.org/documentation/advanced/ffi/

[Documentation index](https://alice-lang.org/documentation/llms.txt) · [Complete book](https://alice-lang.org/llms-full.txt)

Alice calls C with `lib` and `fun` declarations and no glue code. The compiler checks each signature, passes safe
types directly (numbers, `Bool`, `String`, arrays of numbers, structs of numbers), and only asks for `unsafe` where a
raw pointer appears. The design is in [ADR 0018](https://github.com/alicelanguage/alice/blob/main/archicture/adr/0018-ffi-blittable-wrappers.md).

```alice
struct Timespec
  getter sec : Int64
  getter nsec : Int64
  def initialize(@sec : Int64, @nsec : Int64)
  end
end

@[Link("libc.so.6")]
lib LibC
  fun strlen(s : String) : UInt64                      # String crosses as UTF-8 on a stack buffer, no allocation
  fun getenv(name : String) : String?                  # borrowed char*: decoded, never freed; NULL is nil
  fun clock_gettime(clock : Int32, out ts : Timespec) : Int32
  fun qsort(base : Array(Int32), n : UInt64, size : UInt64, cmp : Callback(Pointer(Int32), Pointer(Int32), Int32)) : Void
end

puts "strlen(\"héllo\") = #{LibC.strlen("héllo")}"        # 6 bytes in UTF-8
puts "has PATH: #{!LibC.getenv("PATH").nil?}"
LibC.clock_gettime(0, out now)
puts "clock ok: #{now.sec > 0}"

xs = [42, 7, 19, 3, 25]
LibC.qsort(xs, 5_u64, 4_u64, ->(a : Pointer(Int32), b : Pointer(Int32)) { a[0] <=> b[0] })
puts "sorted by C: #{xs.join(", ")}"
```

The library name is platform-specific: use `libc.so.6` on Linux and `/usr/lib/libSystem.B.dylib` on macOS. The
example runs in the repository as `examples/interop/libc.al`.

## What crosses the boundary

| `fun` type                    | Crosses as                                                                                                                                                    |
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| numbers, `Char`               | themselves (a direct call)                                                                                                                                    |
| `Bool`                        | a one-byte C `bool`                                                                                                                                           |
| `String`, `String?` parameter | NUL-terminated UTF-8 on every OS, in a stack buffer of up to 85 characters; `nil` is `NULL`; an embedded NUL raises `ArgumentException` instead of truncating |
| `String?` result              | a borrowed UTF-8 `char*`, decoded and never freed; `NULL` is `nil`. A `String` result raises on `NULL`                                                        |
| `Array(number)` parameter     | a pointer to the pinned elements, with no copy                                                                                                                |
| `Callback(A, B, R)` parameter | a C function pointer; see below                                                                                                                               |
| `out x : T` / `ref x : T`     | a pointer to the caller's variable, pinned for the call                                                                                                       |
| `struct` of numbers           | by value, with C layout (fields in declaration order)                                                                                                         |
| `Pointer(T)`                  | a raw pointer, only inside `unsafe`                                                                                                                           |

Passing `out now` declares `now` at the call site with the declared type. A value passed by `out` or `ref` is
written by C before the call returns, so read it afterwards, not before.

## Callbacks

A `Callback(A, B, R)` parameter takes a lambda literal. The compiler lifts the lambda to a static
`[UnmanagedCallersOnly]` method, so no delegate or GC handle is created and the call site needs no `unsafe`:

```alice
LibC.qsort(xs, 5_u64, 4_u64, ->(a : Pointer(Int32), b : Pointer(Int32)) { a[0] <=> b[0] })
```

- A lambda that captures a local variable is error AL0215. C has no closure, so pass state through the
  function's user-data argument instead.
- An exception raised inside the callback is caught and rethrown once the C call returns, so it does not
  terminate the process.

## Pointers and unsafe

`Pointer(T)` values, such as the result of `fun malloc(n : UInt64) : Pointer(UInt8)` or `p[i]` on a pointer,
are allowed only inside `unsafe ... end` or an `unsafe def`. Elsewhere they are a compile error with a hint (AL0216).
Strings, arrays and numbers need no `unsafe`, so most C interop does not need it at all.

## Performance

Every import is blittable behind an inlined wrapper, so there are no marshalling stubs and NativeAOT has none to
precompile. Signatures over numbers and `Bool` need no stub at all, and a `Bool` call is 2.7x faster than it was
before 0.12.2. A 12-character string costs 15.5 ns per call, against 15.6 ns for .NET's own UTF-8 marshaller. Mark a
short, non-blocking C function `@[Fast]` to skip the GC transition as well.

Batch work into one call where you can: one call over an array does less work than one call per element.

## Tests

The compiler and runtime tests cover this area: `FfiTests` (the forms above, including `LibraryImport` through a `partial def`),
and `FfiStressTests` (UTF-8 at the stack-buffer boundary, lone surrogates, 8 threads making 20,000 string calls each, and repeated
callback exceptions).

## Continue reading

- Previous: [Ownership and reused buffers](https://alice-lang.org/documentation/advanced/ownership.md)
- Next: [Editor setup](https://alice-lang.org/documentation/tools/editors.md)
