Lua 提供了调用 C 函数的接口,这样我们可以开心地用 C 来写一些底层的代码供 Lua 调用了。这里将整个流程整理一下。
新建 C 源文件,将需要被 Lua 调用的函数实现一下,这里实现一个简单的传值函数。
/**
* 简单地对传入参数加 1,并返回结果
*/
int l_plus_one(lua_State *L)
{
// 获取函数参数:从栈底取一个参数
long long k = lua_tointeger(L, 1);
// 函数主体:做加 1 操作
++k;
// 函数结果返回:将结果压进栈顶
lua_pushinteger(L, k);
// 函数结果返回:表示在从栈顶算起,有 1 个值是返回值
return 1;
}
上面有几点需要注意
* 函数的原型是固定的:int (*l_func)(lua_State*)
* 返回类型为 int,表示在 lua 中调用该函数时获得的返回值个数
* 函数参数 lua_State,lua 和 C 通信时用到的上下文
* lua 模块在调用的 C 函数时,每一个函数都分配了一个在 C 和 Lua 之间传递参数的栈,用作参数和返回值传递用。
假设我们的 C 模块文件名叫做 mylib
/**
* 函数集的结构体
*/
struct luaL_Reg funcs[] =
{
{ "plus_one", l_plus_one },
{ NULL, NULL }
};
/**
* Lua 模块默认调用的初始化函数
*/
__declspec(dllexport) int luaopen_mylib(lua_State *L)
{
// 在栈中新建一个表
lua_newtable(L);
// 将函数存入表中
luaL_setfuncs(L, funcs, 0);
// 表示 Lua 端能收到一个返回值,即这个表
return 1;
}
* 我们一定要在 C 模块中定义 int luaopen_mylib(lua_State*) 这个函数名的函数,因为 lua 加载 C 模块时会自动调用它
* 这个函数是两个模块交互的关键。在这个函数里面,我们使用 Lua 提供的那些 capi 来往栈里放任何东西,Lua 端就可以取到了
* 这里我们当然是放上面的那个函数了
* 在老版本下 (5.2以下)我们会直接在这个函数中加载上面写的那个函数到全局空间中。可以参考这里 点击打开链接
在 luaopen_mylib 函数中写好到处部分后,我们需要将 C 源文件编译成动态库给 Lua 加载,windows 下把项目类型设置成 dll 再编译就行了。
Lua 中使用
local l = require "mylib"
* Lua 模块调用时会搜索 cpath 中的 mylib.dll(Windows)/mylib.so(Linux),并加载到内存中
* Lua 模块会调用动态库中的 luaopen_mylib 函数一次,这些都是默认好的
按照我们上面 luaopen_mylib 这个函数的写法,返回结果应该是一个,是存放函数集的表,我们把它赋值给 l。
调用函数
local ret = l.plus_one(2)
如果调用成功的话 ret 值应该是 3 了
运行环境:windows/lua 5.3/msvc 11.0