LUA调用C(一)-----CAPI
一:为什么要使用Lua调用C函数
在lua中调用C函数可以提高程序的运行效率。所以lua与C的相互调用在工程中相当实用,本文就来讲解lua与C相互调用的方法。
二:Lua调C函数实现原理
Lua与C相互调用的首要问题是如何交换数据,lua API使用了一个抽象的栈与C语言交换数据,提供了压入元素,查询元素和弹出元素等功能的API操作栈,这里可以查看lua5.2中每个函数的详细文档,栈中的元素可以通过索引访问,从栈底向上是从1开始递增的正整数,从栈顶向下是从-1开始递减的负整数,栈的元素按照FIFO的规则进出。
三:Lua调C
lua可以将C函数注册到lua中,C函数必须遵循统一的原型,这个原型定义在lua.h中。
typedef int (*lua_CFunction)(lua_State* L)
这个函数包含的参数是 lua_State
类型的指针 L 。可以通过这个指针进一步获取通过 Lua 代码传入的参数。这个函数的返回值类型是一个整型,表示返回值的数量。需要注意的是,用 C 编写的函数无法把返回值返回给 Lua 代码,而是通过虚拟栈来传递 Lua 和 C 之间的调用参数和返回值。
用C函数扩展lua时,一般将所有的C函数编译成一个独立的模块,方便增加新的函数。
Demo:
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#include <stdio.h>
//实现函数
static int show_lua(lua_State *L){
const char *str = lua_tostring(L, 1);//获取参数、字符串
//const cahr *lua_tostring(lua_State *L,int index)
//lua_Number(double) lua_tonumber(lua_State *L, int index);//number
int ret = show(str); //调用函数
lua_pushnumber(L, ret); //压入结果
return 1;//返回结果数量
}
//申明一个数组,包含模块中所有的函数及名称。数组元素的类型为luaL_Reg结构
static const struct luaL_Reg mylib[] = {
{"show_lua" , show_lua},
{NULL, NULL}//固定结尾
};
//声明一个主函数,用于创建C模块。函数返回时,会将table留在栈中。
int luaopen_mylib(lua_State *L){
luaL_newlib(L, mylib); //5.2 ,创建(复用)一个table,并用数组ding_lib中的信息填充这个table
//luaL_register(L, "lib",lib); // lua 5.1
return 1; //返回1,表示将这个table返回给Lua
}
//测试的功能函数
int show(char *str)
{
int ret = 0;
if(str == NULL){
ret = -1;
}
else{
printf("输入:%s\n",str);
}
return ret;
}
每个被lua调用的C函数都有自己的私有栈,压入参数的索引从1开始递增,结果值也是直接压入栈中,函数返回时会将压入的参数全部删除,只留下结果值。
mylib[]声明了模块中所有C函数列表,每一项映射了C函数在lua中的命名,比如上面代码中show函数在lua中用show_lua表示,列表必须用{NULL, NULL}结束。
luaL_newlib在栈中创建一个table,将mylib数组中的C函数注册进这个table中。 luaopen_mylib将这个table中的函数加载进lua环境中。
四、编译生成动态库,供Lua调用
gcc -shared -fPIC demo.c -lluajit-5.1 -L /usr/local/openresty/luajit/lib -I /usr/local/openresty/luajit/include/luajit-2.1 -o mylib.so
注:lua代码中,require会查找 mylib.so,并调用该链接库中的 luaopen_mylib,luaopen_的后缀必须与动态链接库名字一样,这是由require查找函数方式决定的。
为了方便我们测试,我们在 LD_LIBRARY_PATH这个环境变量中加入了刚刚库所在的路径
export LD_LIBRARY_PATH=$PWD
五、Lua调用
demo.lua:
local f = require “mylib”
local str = "Hello World"
print(f.show_lua(str))
调用C模块:
lua demo.lua