LUA-C++交互篇-数据传输栈分析
1.lua向c++数据传输过程分析
本部分,我们将会通过图示+代码的方式解读数据的存储结构
1.1 基本数据存储结构
众所周知的,lua常用的数据类型包括:table,number,string
所以,基本数据就为:number,string,复合数据:table
1.2 定义:lua向c++传输数据过程
lua向c传递数据,通过的是栈,这一点毋庸置疑,lua向c++传输数据我们定义为:
1. 一个由c++编写的用来给lua调用的模块,定义为core
2. 当在lua中调用core.xxx(a,b,c)时,我们称从lua将数据传递给了c++
1.3 基本数据类型的数据传输过程
1.3.1 luaToC++测试代码
local core = require("LuaShare")
local v2 = core.setPos(1.1,2.2,3.3);
1.3.2 c++接收数据时,我们讨论的问题
- 数据存储在栈中的的位置?或者数据的表现形式?
- 对于luaL_checknumber(L,1)的数据获取方式
- 对于luaL_checknumber(L,-1)的数据获取方式
a.数据存储在栈中的的位置?或者数据的表现形式?
b.对于luaL_checknumber(L,1)的数据获取方式
在c++中,我们要获取传过来的Lua参数,通常会这样
static int setPos(lua_State* L) {
double l1 = luaL_checknumber(L, 1);
}
我们尝试打印这个数据:
很容易的得出结论:
luaL_checknumber(L,1)中的1,指从栈底开始获取数据,就像这种:
c. 对于luaL_checknumber(L,-1)的数据获取方式
static int setPos(lua_State* L) {
double l1 = luaL_checknumber(L, -1);
cout << setw(5) << l1 << endl;
结果输出
很自然的,我们可以推断:
1.4 table类型数据的传输过程
当我们开始涉足到table的传输,一切都看起来变得非常复杂了...
1.4.1 一个简单的table传输
lua代码:
local core = require("LuaShare")
local vec3 = {x = 1.1,y = 2.2,z = 3.3}
core.setPos(vec3);
现在,我们尝试研究几个问题:
- 此时的虚拟栈中栈的长度是多少?
- 我们怎么捕捉(遍历)这个table的数据?
- 当table类型和number类型及其string类型混合传入时,怎么拆解?
a. 虚拟栈中栈的长度是多少?
你可以使用函数:lua_gettop(lua_State *L);去捕捉这个长度
static int setPos(lua_State* L) {
int len = lua_gettop(L);
cout <<"长度为:"<< len << endl;
return 0;
}
输出结果:
显然,一个table仅占一个坑位
b.怎么去获取(遍历)这个table呢?
方法很简单,将你要访问的table放到栈底就行
如果你只有一个table:
local core = require("LuaShare")
local vec3 = {x = 1.1,y = 2.2,z = 3.3}
local vec4 = {x = 3.1,y =4.2,z = 5.3}
core.setPos(vec3);
typedef unordered_map<string, double> sdmap;
static sdmap checkTable(lua_State *L) {
lua_pushnil(L);
sdmap sdp;
while (lua_next(L, 1) != 0)
{
sdp.insert({ lua_tostring(L, -2) , lua_tonumber(L, -1) });
lua_pop(L,1);
}
lua_remove(L, 1);//将栈底移除
return sdp;
}
//测试代码:
static int setPos(lua_State* L) {
sdmap mp = checkTable(L);
print(mp);
}
结果输出:
如果你存在两个以上的table:
local core = require("LuaShare")
local vec3 = {x = 1.1,y = 2.2,z = 3.3}
local vec4 = {x = 3.1,y =4.2,z = 5.3}
core.setPos(vec3,vec4);
在c++中解析也很方便:
static int setPos(lua_State* L) {
sdmap mp = checkTable(L);
print(mp);
sdmap mpmp = checkTable(L);
print(mpmp);
return 0;
}
结果输出:
如果你同时包括参数和table,建议将table放在栈底(lua的第一个参数),或者在check_number(L,1)后,手动lua_remove(L,1),这个时候table就会放到栈底:
local core = require("LuaShare")
local vec3 = {x = 1.1,y = 2.2,z = 3.3}
local vec4 = {x = 3.1,y =4.2,z = 5.3}
core.setPos("lostArea",vec4);
static int setPos(lua_State* L) {
string db = luaL_checkstring(L, 1);
lua_remove(L, 1);
cout << "check ans = " << db << endl;
sdmap mpmp = checkTable(L);
print(mpmp);
结果输出:
1.5 常见的对数据栈的操作函数
1.5.1 lua_pushnumber(L, 123);
这个函数我们很容易的确定,就是将数据从栈顶压入到栈底,我们接下来进行测试
1. 我们通过该函数压入两个数123,233到数据栈中
2. 我们在lua中用local a,b去接收这两个数
请猜测:
a = 123还是233?
c++代码:
static int setPos(lua_State* L) {
lua_pushnumber(L, 123);
lua_pushnumber(L, 233);
return 2;//返回的参数数量
}
lua代码:
local core = require("LuaShare")
local a,b = core.setPos()
print(a)
print(b)
测试结果:
我们可以得出结论:
返回的数据顺序是一个队列的这样一个顺序:先进先出
类似操作的函数还有
lua_pushnil(lua_State*);
lua_pushboolean(lua_State*, bool);
lua_pushnumber(lua_State*, lua_Number);
lua_pushinteger(lua_State*, lua_Integer)
lua_pushlstring(lua_State*, const char*, size_t);
lua_pushstring(lua_State*, const char*);