如果需要在lua中需要能够调用cpp的代码,
local testlib = require("testlib")
testlib.luacallcfunc()
那么在cpp中这样写
extern "C" {
#include "lua/lauxlib.h"
#include "lua/lua.h"
#include "lua/lualib.h"
}
#include <iostream>
static int lluacallcfunc(lua_State *L) {
std::cout << "hello in cpp" << std::endl;
return 0;
}
static const struct luaL_Reg testlib[] = {
{"luacallcfunc",lluacallcfunc},
{NULL, NULL}
};
static int luaopen_testlib(lua_State *L) {
luaL_newlib(L,testlib);
return 1;
}
int main(int argc, char **argv) {
lua_State *L = luaL_newstate();
luaL_openlibs(L);
luaL_requiref(L, "testlib", luaopen_testlib, 0);
char *luafile = argv[1];
luaL_dofile(L, luafile);
lua_close(L);
return 0;
}
如果lua需要带参数
testlib.luacallcfunc(12,"abc")
那么在cpp中
static int lluacallcfunc(lua_State *L) {
int intv = lua_tonumber(L, 1);//传入的第一个参数为int
const char *szStr = lua_tostring(L, 2); //传入的第二个参数为string
return 0;
}
如果lua函数有返回结果
local a = testlib.luacallcfunc(12,"abc") --a=10
那么在cpp中
static int lluacallcfunc(lua_State *L) {
int intv = lua_tonumber(L, 1);//传入的第一个参数为int
const char *szStr = lua_tostring(L, 2); //传入的第二个参数为string
lua_pushnumber(L,10);
return 1;//这里是lua函数返回值的个数
}
如果lua的参数是一个table,那么使用lua_gettable等函数来获取。
这里需要介绍一下栈
其中栈底上标是1,2,3,4
栈顶下标可以用 -1,-2,-3,-4来表示
如图
当调用了
testlib.luacallcfunc(12,"abc")时,栈上的内容为
当在cpp里调用 lua_pushnumber(L,10);时
如果 参数是table呢
假设在lua中调用了
testlib.luacallcfunc(12,"abc",{a="cba"})
这时在cpp 中
lua_pushstring(L,"a"); 将key推到栈顶
再调用 lua_gettable(L, tIdx);会变成
这时就可以把那个值取出来了。
当用完之后,需要回退之前的栈的内容。
则调用lua_pop(L, 1);这时
总结:
lua与c传递数据是通过一个叫栈的数据结构来进行的。
其中栈底上标是1,2,3,4
栈顶下标可以用 -1,-2,-3,-4来表示(其实也可以 用 栈长-1,栈长-2..来表示)
栈底的数据可以认为是lua传给c的(简单数据类型的数据可通过lua_toxxx(L,idx)来获取)。
相对,在函数的return value中,表示栈顶value个数据是c传给lua的(即在lua函数调用库函数时的返回值)。
往栈顶上塞数据可以用lua_pushxxx 来实现。
当然栈顶的数据也还可以被其它函数修改。(具体就要看lua的api了)
所以如果有调用那些函数,栈顶在运行的过程中数据是时不时在变化的。
当你获取完栈顶的数据,然后又不需要它时,调用一下lua_pop(L,1),即可把栈顶数据pop掉。
如果有使用修改栈顶数据的函数,需要知道每一行代码运行后,栈顶的数据是什么。
下面是完整的代码
extern "C" {
#include "lua/lauxlib.h"
#include "lua/lua.h"
#include "lua/lualib.h"
}
static int getTableIntValue(lua_State *L, int tIdx, const char *key) {
lua_pushstring(L, key);//将key推到栈顶
lua_gettable(L, tIdx);//将t[key]推到栈顶,并把key移走( 不知道先走哪一步 )
int ret = lua_tonumber(L, -1); //把值给弄出来
lua_pop(L, 1);//把栈顶元素移走,恢复栈
return ret;
}
static int lluacallcfunc(lua_State *L) {
int intv = lua_tonumber(L, 1);//传入的第一个参数为int
const char *szStr = lua_tostring(L, 2); //传入的第二个参数为string
int tableIdx = 3; //传入的第三个参为是一个table
if (lua_istable(L, tableIdx) == 0) {
lua_pushnil(L);
return 1;
}
int tableStrKeyValue = getTableIntValue(L, tableIdx, "tableStrKey");
const char *arrElemntKey = "arrKey";
lua_pushstring(L, arrElemntKey); //将key推到栈顶
lua_gettable(L, tableIdx); //将t[key]推到栈顶,并把key移走( 不知道先走哪一步 )
size_t len = lua_rawlen(L, -1); //栈顶是一个数组类型的table 可以使用 lua_rawxxx功能
for (size_t i = 1; i <= len; i++) {
lua_rawgeti(L, -1, i); //把 arr[i]推到栈顶 现在栈顶是arr[i]
const char *png = lua_tostring(L, -1);//数组里的元素是一个 string
lua_pop(L, 1); //恢复栈顶,现在栈顶是是 arr
}
lua_pop(L, 1); //恢复栈顶,把arr移走。
int ret = 0;
lua_pushnumber(L, ret);
return 1;
}
static const struct luaL_Reg testlib[] = {
{"luacallcfunc",lluacallcfunc},
{NULL, NULL}
};
static int luaopen_testlib(lua_State *L) {
luaL_newlib(L,testlib);
return 1;
}
int main(int argc, char **argv) {
lua_State *L = luaL_newstate();
luaL_openlibs(L);
luaL_requiref(L, "testlib", luaopen_testlib, 0);
char *luafile = argv[1];
luaL_dofile(L, luafile);
lua_close(L);
return 0;
}
--lua
local function main()
local testlib = require("testlib")
print(testlib.luacallcfunc(1,"abc",{tableStrKey=1,arrKey={"a","b"}}))
end
xpcall(main,print)--当lua有报错的时候,可以打印出来。
会打印出: 0
附:api 注释
void luaL_requiref (lua_State *L, const char *modname,lua_CFunction openf, int glb);
//在lua中 require时,会调用到 openf的函数 glb!=0 时,也注册为全局
typedef int (*lua_CFunction) (lua_State *L);
//能让lua/c 中正确交互的函数
//一个简单的例子:
static int foo (lua_State *L) {
int n = lua_gettop(L); /*变量个数 */
lua_Number sum = 0.0;
int i;
for (i = 1; i <= n; i++) {
if (!lua_isnumber(L, i)) {
lua_pushliteral(L, "incorrect argument");//提示错语信息
lua_error(L);
}
sum += lua_tonumber(L, i);
}
lua_pushnumber(L, sum/n); /*第一个result*/
lua_pushnumber(L, sum); /* 第二个result*/
return 2; /* result 的个数 */
}
void luaL_newlib (lua_State *L, const luaL_Reg l[]);
//新建一个table 并向那个table 注册 所有在 l luaL_Reg 函数
//这个函数实现如下:
(luaL_newlibtable(L,l), luaL_setfuncs(L,l,0))
luaL_Reg 的定义如下
typedef struct luaL_Reg {
const char *name;
lua_CFunction func;
} luaL_Reg;
void luaL_newlibtable (lua_State *L, const luaL_Reg l[]);
//创建 一个table,刚好能把l 里的放进去 注意:这个table 的大小是合适的,但是并没有把l 里的函数给赋过去
void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup);\
//把l里的所有函数注册到 top里的table中去