C interop, 1 of 7
Calling C
Declare C functions in an Extern block and call them like your own, with C's types and out-parameters.
What you’ll build
A program that calls functions from the C runtime, which every FutureBlitz program links:
abs, strlen, atoi under a name of your own, frexp with an out-parameter, and getenv,
which gives back text. It’s the whole of what calling a C library takes: an Extern block that
says what each function takes and gives.
An Extern block
An Extern "C" block declares C functions, one per line, with their parameters and results in
FutureBlitz’s types. There’s no header to include and no wrapper to compile: the program calls
the C symbol directly, through C’s own calling convention.
Import std.core
Extern "C"
Function abs(n: Int32): Int32
Function strlen(text: CString): UInt64
End Extern
Print(abs(-42))
Print(strlen("FutureBlitz"))42 11
An Extern Function is called from ordinary code, like any function. strlen takes a C string,
const char*, which is a CString; a String passed for it is copied with a NUL after it for the
call. Strings and buffers has more.
C’s types
Each C type has a FutureBlitz type of the same size and meaning:
| FutureBlitz | C |
|---|---|
Int8 to Int64, UInt8 to UInt64 | int8_t to int64_t, uint8_t to uint64_t |
CLong, CULong, CWChar | long, unsigned long, wchar_t, at the target’s sizes |
Float32, Float64 | float, double |
Bool | bool |
Ptr<T>, Ptr<Void> | T*, void* |
CString | const char* |
Callback(A, B): R | a function pointer, R (*)(A, B) |
a @CLayout Struct | a struct |
C’s int is an Int32, and size_t a UInt64, on every target FutureBlitz builds for, which
is why strlen gives a UInt64. long differs by OS, so it has a type of its own, CLong:
Import std.core
Extern "C"
Function labs(n: CLong): CLong
End Extern
Print(labs(-1234567))1234567
A name of your own
= "symbol" after a declaration calls the C symbol by a different name in your code.
Import std.core
Extern "C"
Function ParseInt(text: CString): Int32 = "atoi"
End Extern
Print(ParseInt("1234") + 1)1235
Out-parameters
Many C functions return a second result through a pointer. A ByRef parameter passes the
variable’s address, so the call needs no pointers and no Unsafe code. frexp splits a number
into a fraction and a power of two, and writes the power through its int*.
Import std.core
Extern "C"
Function frexp(x: Float64, ByRef exponent: Int32): Float64
End Extern
Local exponent: Int32 = 0
Local fraction = frexp(48.0, ByRef exponent)
Print("48 is {fraction} * 2^{exponent}")48 is 0.75 * 2^6
Text from C
A C function that gives back a const char* can be declared to give a String. The text is
copied into a new String right after the call. String? is for one that can give NULL, which
becomes Null, as getenv does for a variable that isn’t set.
Import std.core
Extern "C"
Function getenv(name: CString): String?
End Extern
Print(getenv("FB_TUTORIAL_NOT_SET") ?? "not set")not set
All of it
Import std.core
Extern "C"
Function abs(n: Int32): Int32
Function strlen(text: CString): UInt64
Function ParseInt(text: CString): Int32 = "atoi"
Function frexp(x: Float64, ByRef exponent: Int32): Float64
Function getenv(name: CString): String?
End Extern
Print(abs(-42), strlen("FutureBlitz"), ParseInt("1234") + 1)
Local exponent: Int32 = 0
Local fraction = frexp(48.0, ByRef exponent)
Print("48 is {fraction} * 2^{exponent}")
Print(getenv("FB_TUTORIAL_NOT_SET") ?? "not set")42 11 1235 48 is 0.75 * 2^6 not set
These functions are in the C runtime. A function from another library names it with Lib, as
Native libraries in project.toml shows. A C function that
breaks memory when it’s given the wrong arguments is declared Unsafe Function, and only Unsafe
code can call it.
What you learned
- An
Extern "C"block declares C functions, which ordinary code calls like its own. - Each C type maps to a FutureBlitz type, with
CLongfor C’slong. = "symbol"gives a C function a name of your own.- A
ByRefparameter is an out-parameter, with no pointers needed. - A function that gives text can give a
String, or aString?when it can give NULL.
The rules are in the language reference.
Report an issue with this page or with FutureBlitz on GitHub.