lua是扩展性很是良好的语言,虽然核心很是精简,可是用户能够依靠lua库来实现大部分工做。除此以外,lua还能够经过与C函数相互调用来扩展程序功能。在C中嵌入lua脚本既可让用户在不从新编译代码的状况下修改lua代码更新程序,也能够给用户提供一个自由定制的接口,这种方法遵循了机制与策略分离的原则。在lua中调用C函数能够提升程序的运行效率。lua与C的相互调用在工程中至关实用,本文就来说解lua与C相互调用的方法。html
Lua与C相互调用的首要问题是如何交换数据,lua API使用了一个抽象的栈与C语言交换数据,提供了压入元素,查询元素和弹出元素等功能的API操做栈,这里能够查看lua5.2中每一个函数的详细文档,栈中的元素能够经过索引访问,从栈底向上是从1开始递增的正整数,从栈顶向下是从-1开始递减的负整数,栈的元素按照FIFO的规则进出。数组
1、 C调用lua函数
先经过一个简单的例子了解C是怎么调用lua的,ui
//test.lua width = 10 height = 20 //test.c #include <stdio.h> #include <lua.h> #include <lualib.h> #include <lauxlib.h> int main() { lua_State *L = luaL_newstate(); luaL_openlibs(L); if(luaL_loadfile(L, "test.lua") || lua_pcall(L, 0,0,0)){ printf("error %s\n", lua_tostring(L,-1)); return -1; } lua_getglobal(L,"width"); lua_getglobal(L,"length"); printf("width = %d\n", lua_tointeger(L,-2)); printf("length = %d\n", lua_tointeger(L,-1)); lua_close(L); return 0; }
luaL_newstate建立一个新的lua_State,C和lua的全部操做都要依赖这个lua环境, luaL_openlibs将lualib.h中定义的lua标准库加载到进lua_State。lua
luaL_loadfile从文件中加载lua代码并编译,编译成功后的程序块被压入栈中,spa
lua_pcall会将程序块弹出并在保护模式下解释执行。代码中调用lua_pcall就在lua_State中定义了 width和 length两个全局变量。code
lua_getglobal将全局变量的值压入栈中,width先入栈,在-2的位置,length在栈顶。htm
除了变量,C代码还能够直接调用lua中定义的函数blog
//test.lua function add(x, y) return x+y end //test.c #include <stdio.h> #include <lua.h> #include <lualib.h> #include <lauxlib.h> #include <math.h> int main() { lua_State *L = luaL_newstate(); luaL_openlibs(L); if(luaL_loadfile(L, "test.lua") || lua_pcall(L, 0,0,0)){ printf("error %s\n", lua_tostring(L,-1)); return -1; } lua_getglobal(L,"add"); lua_pushnumber(L, 10); lua_pushnumber(L, 20); if(lua_pcall(L, 2, 1, 0) != 0){ printf("error %s\n", lua_tostring(L,-1)); return -1; } double z = lua_tonumber(L, -1); printf("z = %f \n", z); lua_pop(L, 1); lua_close(L); return 0; }
lua_pcall(L, 2, 1, 0)表示,传入两个参数,指望获得一个返回值,0表示错误处理函数在栈中的索引值,压入结果前会弹出函数和参数,因此z的索引是-1.索引
2、 lua调用C
lua能够将C函数注册到lua中,C函数必须遵循统一的原型,这个原型定义在lua.h中,
typedef int (*) (lua_State *)
用C函数扩展lua时,通常将全部的C函数编译成一个独立的模块,方便增长新的函数。
//mylib.c #include <stdio.h> #include <lua.h> #include <lualib.h> #include <lauxlib.h> #include <math.h> static int myadd(lua_State *L){ int a = luaL_checknumber(L, 1); int b = luaL_checknumber(L, 2); lua_pushnumber(L, a+b); return 1; } static const struct luaL_Reg mylib [] = { {"add", myadd}, {NULL, NULL} }; int luaopen_mylib(lua_State *L){ luaL_newlib(L, mylib); return 1; } //call.lua #!/usr/local/bin/lua lib=require "mylib" print(lib.add(1, 2))
每一个被lua调用的C函数都有本身的私有栈,压入参数的索引从1开始递增,结果值也是直接压入栈中,函数返回时会将压入的参数所有删除,只留下结果值。mylib[]声明了模块中全部C函数列表,每一项映射了C函数在lua中的命名,好比上面代码中myadd函数在lua中用add表示,列表必须用{NULL, NULL}结束。 luaL_newlib在栈中建立一个table,将mylib数组中的C函数注册进这个table中。 luaopen_mylib将这个table中的函数加载进lua环境中。
先将C代码编译成动态连接库,
gcc -shared -fPIC -o mylib.so mylib.c -llua -lm -ldl
lua代码中,require会查找 mylib.so,并调用该连接库中的 luaopen_mylib,luaopen_的后缀必须与动态连接库名字同样,这是由require查找函数方式决定的。