Lua cannot call an arbitrary C function directly. A callable function must follow the lua_CFunction convention:
1 | typedef int (*lua_CFunction)(lua_State *L); |
Arguments are available on a private stack starting at index 1. The function pushes its results and returns their count. Each invocation gets its own stack frame, including recursive calls.
A small C function
1 |
|
luaL_checknumber both validates and converts the argument. It produces a normal Lua error when the value is invalid. Optional arguments can use helpers such as luaL_optnumber.
Registering the function
An embedding application can expose the function as a global:
1 | lua_pushcfunction(L, l_sin); |
Lua can then call mysin(math.pi / 2). Libraries should normally avoid adding globals and return a module table instead.
Building a module
1 | static const luaL_Reg mathx[] = { |
Compile this as a shared library named for the platform, place it on package.cpath, and load it with:
1 | local mathx = require("mathx") |
The exported loader must be named luaopen_<module>. Exact compiler and linker flags depend on the Lua version and operating system; compile and link against the same Lua ABI used by the host application.
Errors and continuations
Use luaL_error for an invalid operation in a library function. When C calls back into Lua, prefer lua_pcall if the host needs to recover from errors. Yielding across C boundaries requires the continuation APIs, such as lua_yieldk and lua_pcallk; a plain C call frame cannot always be resumed safely.
The central rule is simple: treat the Lua stack as the function’s calling convention, validate every argument, and make ownership of every pushed value explicit.