# C interop

> Declare and call C standard library functions from Brine with extern fn, limited to integer, float and bool arguments and results.

Source: https://docs.brinelang.org/language/c-interop/

`extern fn` declares a function written in C so Brine code can call it. For now an extern function may only take and return integers, floats and bools, and only the C standard library (with the math library) is linked in.

```brine
extern fn cbrt(x: float) -> float
extern fn hypot(x: float, y: float) -> float
extern fn atan2(y: float, x: float) -> float
extern fn llabs(x: i64) -> i64
extern fn toupper(c: i32) -> i32


fn main():
    print(cbrt(27.0), hypot(3.0, 4.0), atan2(1.0, 1.0) * 4.0)
    print(llabs(-42), chr(int(toupper(i32(ord("a"))))))
```

Output

```text
3.0 5.0 3.141592653589793
42 A
```

## Declaring a C function

[Section titled “Declaring a C function”](#declaring-a-c-function)

* Write `extern fn name(params) -> type` at the top level, with no body. `name` is the C symbol, exactly as written.
* Parameter and return types must be integer types (`int`/`i64`, `i32`, `u8`, …), floats (`float`/`f64`, `f32`) or `bool`. The return type may be left out for a C function that returns `void`.
* Call it like any Brine function.

Match the C types exactly, because Brine trusts the declaration:

| C                          | Brine             |
| -------------------------- | ----------------- |
| `int`                      | `i32`             |
| `unsigned int`             | `u32`             |
| `long long`, `int64_t`     | `i64` (= `int`)   |
| `size_t` on 64-bit systems | `u64`             |
| `double`                   | `float` (= `f64`) |
| `float`                    | `f32`             |
| `bool` (C99 `_Bool`)       | `bool`            |
| `void` result              | no `->`           |

C’s `long` is 32 bits on Windows and 64 bits on Linux and macOS, so prefer functions that use `int`, `long long` or fixed-width types (`llabs`, not `labs`).

## What’s not supported

[Section titled “What’s not supported”](#whats-not-supported)

Strings, arrays, pointers, structs, callbacks and variadic functions (`printf`) can’t cross the boundary, and `ref` and `mut` parameters aren’t allowed:

```brine
extern fn puts(s: str) -> i32


fn main():
    puts("hi")
```

```text
error[E0311]: extern functions may only take integers, floats and bools
 --> main.br:1:16
  |
1 | extern fn puts(s: str) -> i32
  |                ^ parameter has type `str`
  = run `brine explain E0311` for more about this error
error: could not compile due to 1 error
```

There is also no way yet to link other C libraries or your own C files: the program links against the C standard library and the math library (on Linux and macOS also `pthread` and `dl`).

`brine check` doesn’t link, so a misspelled or missing C function shows up only when you build or run, as error E0705 naming the undefined symbol:

```text
error[E0705]: linking the program failed
  = note: ... undefined reference to `no_such_c_function'
```

## What Brine knows about C calls

[Section titled “What Brine knows about C calls”](#what-brine-knows-about-c-calls)

Brine can’t see inside a C function, so:

* The prover knows nothing about the result beyond its type. Add an `assert` to hand it a fact: `let r = rand()` then `assert r >= 0`.
* The compiler allows extern calls inside `par`. Only call functions there that are safe to call from several threads at once. Pure math functions like `cbrt` are; `rand` is not.
* In a [`world`](/parallelism/overview/) program, a value returned by C may differ between ranks, so it counts as rank-dependent and can’t decide whether a `world` call happens ([E0510](/reference/errors/#e0510)):

```brine
extern fn rand() -> i32


fn main():
    if rand() % 2 == 0:
        world.barrier()
```

```text
error[E0510]: some ranks might not reach this communication
 --> main.br:5:9
  |
5 |         world.barrier()
  |         ^^^^^^^^^^^^^^^ calls `world.barrier`
4 |     if rand() % 2 == 0:
  |        --------------- this may differ between ranks
  |
  = note: every rank must make the same `world` calls in the same order, otherwise the program could hang
  = help: move the call out of the rank-dependent branch or loop; compute rank-specific values first, then communicate on every rank
  = run `brine explain E0510` for more about this error
error: could not compile due to 1 error
```

Related: [built-in functions](/language/builtins/) (most math is built in: `sqrt`, `sin`, `exp`, `pow`, …), [functions](/language/functions/), [proofs](/proofs/overview/).
