An exported function is a function made visible outside the current Zig program.
Exported Functions
An exported function is a function made visible outside the current Zig program.
Normally, functions only exist inside the compiled program itself.
Example:
fn add(a: i32, b: i32) i32 {
return a + b;
}This function is internal.
Other programs cannot see it.
An exported function changes that.
Example:
export fn add(
a: i32,
b: i32,
) i32 {
return a + b;
}Now the function becomes part of the program’s external binary interface.
Other languages and programs may call it.
What “Exported” Means
When a program is compiled, functions become machine-code symbols.
Most symbols are private.
Exporting a function makes its symbol public.
Conceptually:
normal function
-> internal only
exported function
-> visible externallyThis is essential for:
- shared libraries
- plugins
- C interoperability
- operating systems
- embedded firmware
- game engines
A Simple Exported Function
export fn multiply(
a: i32,
b: i32,
) i32 {
return a * b;
}The keyword:
exporttells the compiler:
make this symbol externally visibleExporting Shared Libraries
Exported functions are commonly used when building dynamic libraries.
Example conceptually:
math.dll
libmath.so
libmath.dylibThese libraries expose functions other programs can call.
Example exported API:
export fn add(
a: i32,
b: i32,
) i32 {
return a + b;
}A C program could call this function.
Why Exported Functions Usually Use C ABI
Binary compatibility matters.
Most exported APIs use:
callconv(.C)Example:
export fn add(
a: i32,
b: i32,
) callconv(.C) i32 {
return a + b;
}This ensures compatibility with C and many other languages.
Without ABI agreement, external calls may fail.
Exported Symbols
Suppose we compile:
export fn hello() void {
}The binary may contain a symbol like:
helloExternal programs can locate and call this symbol dynamically.
Exported Functions and Shared Libraries
Building a shared library conceptually:
zig build-lib math.zig -dynamicThis produces a dynamic library.
Inside:
export fn add(
a: i32,
b: i32,
) callconv(.C) i32 {
return a + b;
}Now other languages may load the library and call add.
Example: Calling from C
Zig library:
export fn square(
x: i32,
) callconv(.C) i32 {
return x * x;
}C program:
#include <stdio.h>
int square(int x);
int main() {
printf("%d\n", square(5));
}This interoperability is one of Zig’s major strengths.
Exporting Variables
Zig can export variables too.
Example:
export var counter: i32 = 0;Now external programs may access:
counterdirectly from the binary.
This is less common but sometimes useful.
Exported Constants
Constants can also be exported.
Example:
export const version: i32 = 1;This allows external systems to inspect metadata.
Export Names
By default, the exported symbol name matches the Zig function name.
Example:
export fn hello() void {
}exports:
helloSome systems allow custom exported names.
This matters when integrating with existing APIs.
Exporting for Plugins
Plugins commonly use exported entry points.
Example conceptually:
export fn pluginInit() void {
}A host application dynamically loads the library and searches for:
pluginInitThis is common in:
- game engines
- browsers
- editors
- audio systems
Exported Functions and Operating Systems
Operating systems frequently depend on exported symbols.
Examples:
- kernel APIs
- driver interfaces
- bootloader entry points
- system calls
Low-level software heavily relies on stable binary interfaces.
Exported Functions and WASM
WebAssembly modules also use exports.
Example conceptually:
export fn update() void {
}JavaScript may call:
wasm.exports.update()Exports are one of the core mechanisms in WASM interoperability.
Exported Functions and Embedded Systems
Embedded firmware often exports known entry symbols.
Examples:
ResetHandler
InterruptHandler
mainThe hardware or bootloader expects exact symbol names.
Public vs Exported
Important distinction:
| Keyword | Meaning |
|---|---|
pub | visible to Zig modules |
export | visible at binary level |
Example:
pub fn helper() void {
}Other Zig files can use it.
But external programs cannot.
Example:
export fn api() void {
}Now the function becomes externally visible in the compiled binary.
Using Both pub and export
Sometimes both are used:
pub export fn api() void {
}This makes the function visible:
- inside Zig modules
- outside the binary
Exported Functions and Safety
Exported functions should use stable, simple types.
Good exported API types:
| Good | Why |
|---|---|
| integers | stable ABI |
| floats | stable ABI |
| pointers | stable ABI |
| C structs | predictable layout |
Bad exported API types:
| Risky | Why |
|---|---|
| Zig-specific internals | ABI instability |
| complex generic types | language-dependent |
| allocator-heavy abstractions | ownership confusion |
Stable binary interfaces require careful design.
Name Mangling
Some languages modify symbol names internally.
This is called name mangling.
C avoids heavy mangling, which is why C ABI compatibility is so universal.
Zig exported C-style APIs usually avoid complicated mangling too.
Dynamic Loading
Programs may load exported functions at runtime.
Example conceptually:
load library
find symbol
call functionThis is how many plugin systems work.
A Complete Example
const std = @import("std");
export fn add(
a: i32,
b: i32,
) callconv(.C) i32 {
return a + b;
}
export fn subtract(
a: i32,
b: i32,
) callconv(.C) i32 {
return a - b;
}
pub fn main() void {
const x = add(10, 5);
const y = subtract(10, 5);
std.debug.print(
"{} {}\n",
.{ x, y },
);
}Output:
15 5The functions work normally inside Zig while also being available externally.
Mental Model
An exported function is:
a public machine-level entry pointNormal functions exist only inside the program.
Exported functions become visible to:
- other programs
- shared libraries
- operating systems
- foreign languages
- plugin systems
This makes exported functions one of the foundations of interoperability and systems programming.