Lua & C 交互 3 c/c++调用lua
来源:互联网 发布:淘宝银行卡怎么解绑 编辑:程序博客网 时间:2024/04/29 18:55
通过c读取lua中的数据,还是从lua的栈上面提取数据
新建一个test.lua文件
str = "hello world!"num = 10b = true t = { id = 1, name = "sammy"}function testAdd(a,b) print("a ="..a," b ="..b) return a + bend
lua文件里面写了字符串,数字,布尔值,table 和函数,通过lua_getglobal函数读取出来
int lua_getglobal(lua_State *L, const char *name)
将name值压入栈中,由lua查找,然后将找到的变量值返回到栈顶,然后我们可以通过lua_toxxx函数获得栈里面查找到的值
1.读取字符串,数字,布尔变量
#include <iostream>extern "C" {#include <lua.h> #include <lauxlib.h> #include <lualib.h> }int main(){ lua_State *L = luaL_newstate(); if (!L) return 1; luaL_openlibs(L); if (luaL_loadfile(L, "test.lua") || lua_pcall(L, 0, 0, 0)) { std::cout << "error:" <<lua_tostring(L,-1)<< std::endl; lua_close(L); return 1; } std::cout << "current top index = "<< lua_gettop(L) << std::endl; //读取数字 lua_getglobal(L, "num"); //查找变量num std::cout << "num is number? " << lua_isnumber(L, -1) << std::endl; int num = lua_tonumber(L, -1);//栈顶存放着num的值,通过负数索引-1直接访问栈顶 std::cout << "num = " << num << std::endl; std::cout << "current top index = " << lua_gettop(L) << std::endl; lua_close(L); return 0;}
输出:
current top index = 0
current top index = 1
num is numberType? 1
num = 10
可以看到在使用lua_getglobal函数后,当前栈的长度变为1,栈顶存放着lua里面num变量的值
继续读取字符串,和布尔变量
//读取字符串 lua_getglobal(L, "str"); std::cout << "current top index = " << lua_gettop(L) << std::endl; std::cout << "str is stringType? " << lua_isstring(L, -1) << std::endl; std::string str = lua_tostring(L, -1); std::cout << "str = " <<str.c_str()<< std::endl; std::cout << "" << std::endl; //读取布尔值 lua_getglobal(L, "b"); std::cout << "current top index = " << lua_gettop(L) << std::endl; std::cout << "b is booleanType? " << lua_isboolean(L, -1) << std::endl; bool b = lua_toboolean(L, -1); std::cout << "b = " << b << std::endl; std::cout << "" << std::endl;
输出:
current top index = 0
current top index = 1
num is numberType? 1
num = 10
current top index = 2
str is stringType? 1
str = hello world!
current top index = 3
b is booleanType? 1
b = 1
此时栈的情况可以一目了然地看出来了
2.读取lua中的table
lua文件中,我们有一个table
t = { id = 1, name = "sammy"}
读取lua的table变量,table里面有两个字符串的key,我们可以用过lua_pushstring将key压入栈中,然后使用lua_gettable(lua_State *L, int index)函数查找t[key],然后弹出栈上的key值,将查找的结果放入key刚存放的栈的位置
lua_getglobal(L, "t");//t现在存放在索引-1(栈顶)位置 lua_pushstring(L, "id");//将key压栈 lua_gettable(L, -2);//这时候t位置就不再栈顶了,索引变为-2 int id = lua_tonumber(L, -1);//弹出栈的key,将找到的结果放入与key相同的栈的位置 lua_pushstring(L, "name");//同理查找key = name的值 lua_gettable(L, -3); std::string name = lua_tostring(L, -1); std::cout << "t = {\n id = " << id << ",\n name = " << name.c_str() << " \n}" << std::endl;
输出:
t = {
id = 1,
name = sammy
}
还有一个函数lua_getfield(lua_State *L, int index, const char *k)(5.1引入的) 等价与上面的
lua_pushstring(L, "id");lua_gettable(L, -2);
示例代码:
lua_getglobal(L, "t"); lua_getfield(L, -1, "id"); int id = lua_tonumber(L, -1); lua_getfield(L, -2, "name"); std::string name = lua_tostring(L, -1); std::cout << "t = { id = " << id<<",name = " << name.c_str() <<"}"<< std::endl;
lua中的table分为array 和map部分,在试这读取一个array部分的table
修改test.lua
t = {3,4,5,6}
同理,将key压入栈中,然后调用lua_gettable,只不过key不再是字符串,而是正整数了
lua_getglobal(L, "t"); lua_pushnumber(L, 1); lua_gettable(L, -2); int value1 = lua_tonumber(L, -1); lua_pushnumber(L, 2); lua_gettable(L, -3); int value2 = lua_tonumber(L, -1); lua_pushnumber(L, 3); lua_gettable(L, -4); int value3 = lua_tonumber(L, -1); std::cout << "t = {\n "<<value1<<","<<value2<<","<<value3<<" \n}" << std::endl;
输出:
t = {
3,4,5
}
遍历lua table
有时候并不会知道lua中的table里面究竟有多少值,这时候就需要通过遍历获得其中的值
通过使用lua_next函数遍历table
int lua_next (lua_State *L, int index);
这个函数会从index位置取得要遍历的table,返回值,先将key压入栈中,然后将value压入栈中,这时候key索引为-2,value索引-1
lua_getglobal(L, "t"); lua_pushnil(L); while (lua_next(L, -2) != 0) { //此时栈的情况就是 -1 value -2 key -3 table std::cout << "key = " << lua_tonumber(L, -2) << ",value = " << lua_tonumber(L, -1) << std::endl; lua_pop(L, 1); }
输出:
key = 1,value = 3
key = 2,value = 4
key = 3,value = 5
在调用lue_next前,先pushnil进去,这就要先看lua中next的用法,就知道原因了
next (table [, index])
运行程序来遍历表中的所有域。 第一个参数是要遍历的表,第二个参数是表中的某个键。 next 返回该键的下一个键及其关联的值。 如果用 nil 作为第二个参数调用 next 将返回初始键及其关联值。 当以最后一个键去调用,或是以 nil 调用一张空表时, next 返回 nil。 如果不提供第二个参数,将认为它就是 nil。 特别指出,你可以用 next(t) 来判断一张表是否是空的。
索引在遍历过程中的次序无定义, 即使是数字索引也是这样。 (如果想按数字次序遍历表,可以使用数字形式的 for 。)
当在遍历过程中你给表中并不存在的域赋值, next 的行为是未定义的。 然而你可以去修改那些已存在的域。 特别指出,你可以清除一些已存在的域。
压入一个nil进入栈中,lua_next函数返回初始key和value了
尝试push一个key = 1值进去
lua_getglobal(L, "t"); lua_pushnumber(L,1); while (lua_next(L, -2) != 0) { std::cout << "key = " << lua_tonumber(L, -2) << ",value = " << lua_tonumber(L, -1) << std::endl; lua_pop(L, 1); }
输出:
key = 2,value = 4
key = 3,value = 5
在遍历中,在遍历中会调用lua_pop来弹出1个元素,这里将value弹出,此时栈顶的值就变成key了,为下一次next函数做准备
遍历包含array和map部分的table示例
test.lua文件:
t = { 1,2,3,4, id = 23, name = "tom", age = 20,}
c++代码(其实还少了好几个类型的判断,真正读取lua中的table的时候,根据实际情况来遍历)
lua_getglobal(L, "t"); lua_pushnil(L); while (lua_next(L, -2) != 0) { std::string keyType = lua_typename(L, lua_type(L, -2)); std::string valueType = lua_typename(L, lua_type(L, -1)); if (keyType == std::string("number")) { std::cout << "key = " << lua_tonumber(L, -2); } else if (keyType == std::string("string")) { std::cout << "key = " << lua_tostring(L, -2); } if (valueType == std::string("number")) { std::cout << ",value = " << lua_tonumber(L, -1) << std::endl;; } else if (valueType == std::string("string")) { std::cout << ",value = " << lua_tostring(L, -1) << std::endl;; } lua_pop(L, 1); }
输出:
key = 1,value = 1
key = 2,value = 2
key = 3,value = 3
key = 4,value = 4
key = id,value = 23
key = name,value = tom
key = age,value = 20
3.调用lua中的函数
c调用lua的函数,方法和上面差不多,就是取出函数压入栈中后,更具函数需要什么参数,往栈里面压入函数需要参数
int lua_pcall (lua_State *L, int nargs, int nresults, int msgh);
以保护模式调用一个函数。
nargs 和 nresults 的含义与 lua_call 中的相同。 如果在调用过程中没有发生错误, lua_pcall 的行为和 lua_call 完全一致。 但是,如果有错误发生的话, lua_pcall 会捕获它, 然后把唯一的值(错误消息)压栈,然后返回错误码。 同 lua_call 一样, lua_pcall 总是把函数本身和它的参数从栈上移除。
如果 msgh 是 0 , 返回在栈顶的错误消息就和原始错误消息完全一致。 否则, msgh 就被当成是 错误处理函数 在栈上的索引位置。 (在当前的实现里,这个索引不能是伪索引。) 在发生运行时错误时, 这个函数会被调用而参数就是错误消息。 错误处理函数的返回值将被 lua_pcall 作为错误消息返回在堆栈上。
典型的用法中,错误处理函数被用来给错误消息加上更多的调试信息, 比如栈跟踪信息。 这些信息在 lua_pcall 返回后, 由于栈已经展开,所以收集不到了。
lua_pcall 函数会返回下列常数 (定义在 lua.h 内)中的一个:
LUA_OK (0): 成功。
LUA_ERRRUN: 运行时错误。
LUA_ERRMEM: 内存分配错误。对于这种错,Lua 不会调用错误处理函数。
LUA_ERRERR: 在运行错误处理函数时发生的错误。
LUA_ERRGCMM: 在运行 __gc 元方法时发生的错误。 (这个错误和被调用的函数无关。)
最后函数运行返回的结果,会压入栈中
//调用lua函数 lua_getglobal(L, "testAdd");//将获得函数压栈 lua_pushnumber(L, 15);//第一个参数压栈 lua_pushnumber(L, 24);//第二个参数压栈 if (lua_pcall(L, 2, 1, 0))//调用lua_pcall(L,参数个数,返回值个数,msgh) { std::cout << "error:" << lua_tostring(L, -1)<< std::endl; lua_close(L); return 1; } if (lua_isnumber(L, -1))//调用成功后,将结果压入栈中 { int value = lua_tonumber(L, -1); std::cout << "testAdd:value = " << value << std::endl; }
输出:
a =15 b =24
testAdd:value = 39
调用多个返回值的lua函数的示例
test.lua文件
function test(a,b) print("a ="..a," b ="..b) return a + b,a-bend
c++代码
lua_getglobal(L, "test"); lua_pushnumber(L, 15); lua_pushnumber(L, 24); if (lua_pcall(L, 2, 2, 0)) //第三个参数改为2表示有2个返回值 { std::cout << "error:" << lua_tostring(L, -1) << std::endl; lua_close(L); return 1; } std::cout << "test = " << lua_tonumber(L, -2) << "," << lua_tonumber(L, -1) << std::endl; //在lua中先返回第一个值压入栈中,然后第二个值返回,压入栈中,此时返回值1索引-2,返回值2索引-1
输出:
a =15 b =24
test = 39,-9
- 【Lua C交互】3 - lua调用C模块
- Lua & C 交互 3 c/c++调用lua
- 【Lua C交互】2 - C调用lua模块
- 【Lua】Lua与C交互
- Lua 与C交互
- Lua 与 C 交互
- C和lua交互
- lua和C交互
- Lua 与C交互
- Lua 与C交互
- Lua 与C交互
- Lua 与 C 交互
- c++&lua交互
- lua与c交互
- C与lua交互
- Lua与C交互
- lua与c交互
- C加载lua配置,table交互, 调用lua函数
- Lua & C 交互 2 尝试操作lua栈
- 耕耘
- cocos2dx 音频模块分析(1):背景音乐
- 四大基本组件之Activity
- Android 操作SQLite基本用法介绍
- Lua & C 交互 3 c/c++调用lua
- android studio的assets目录下存放ttf字体格式的问题
- JavaWeb学习总结(一)——JavaWeb开发入门
- 学习shell编程笔记(二)
- HDU 相遇周期
- Android应用程序互保方案
- android异步加载之Handler、AsyncTask(一)
- Android studio正确配置AndroidAnnotation注解
- leetcode-326-Power of Three