本文介绍如何使用 Lua 的原生 C API 与 C++ 进行数据交互。Lua 和 C/C++ 之间的通信主要依赖 lua_State 这个虚拟栈:所有数据交换,包括调用函数、读取变量、传递参数和取回返回值,都是通过向这个栈压入和弹出数据来完成的。
Lua 栈的基本规则
在开始写代码前,先弄清楚 Lua 栈几个容易踩坑的特性。
- Lua 栈的 index 是自下而上递增的,例如栈中依次有 6 个元素时,从底到顶的 index 为
1 2 3 4 5 6。 - Lua 栈的 index 是"双向循环"的:从栈顶往下看,可以用正数也可以用负数。例如某次状态下,从上到下的 index 依次是
3 2 1 0 -1 -2 -3,对应的栈中的值可能是:1 2 3 x 1 2 3 - 当 Lua 函数返回多个值时,这些返回值会按顺序依次入栈。比如函数
return a, b, c,调用方取栈顶及往下依次得到的关系是a = 3, b = 2, c = 1,也就是第一个返回值最先入栈、最靠近栈底。
栈的清理:lua_pop
函数调用完成后,通常需要手动清理返回值占用的栈空间,使用 lua_pop(x),其中 x 表示要弹出的元素个数。一般情况下函数只有一个返回值时使用 lua_pop(1)。
需要注意:调用 Lua 函数时,参数入栈过程并不会自动保持堆栈平衡,函数执行结束后参数槽位已经由 Lua 内部清理完毕,调用方需要处理的只是返回值占用的那部分栈空间。
C++ 读取 Lua 数据的完整示例
下面是一段 C++ 调用 Lua 函数并读取全局变量的示例代码。它展示了 lua_getglobal、lua_pushnumber、lua_call、lua_tonumber、lua_gettop 以及 lua_pop 这些核心 API 的典型用法。
extern "C"{
#include "src/lualib.h"
#include "src/lauxlib.h"
#include "src/lua.h"
}
#include "iostream"
using namespace std;
lua_State*l;
int get_sum(int x, int y)
{
int sum=0;
lua_getglobal(l, "get_sum");/*调用函数*/
lua_pushnumber(l, x);
lua_pushnumber(l, y);
lua_call(l, 2, 3);/*参数2个,返回值3个*/
cout << "top is " << lua_gettop(l) << endl;
cout << lua_tonumber(l, lua_gettop(l) - 0) << endl;
cout << lua_tonumber(l, lua_gettop(l) - 1) << endl;
cout << lua_tonumber(l, lua_gettop(l) - 2) << endl;
cout << lua_tonumber(l, lua_gettop(l) - 2) << endl;
cout << lua_tonumber(l, lua_gettop(l) - 3) << endl;
cout << lua_tonumber(l, lua_gettop(l) - 4) << endl;
cout << lua_tonumber(l, lua_gettop(l) - 5) << endl;
cout << lua_tonumber(l, lua_gettop(l) - 6) << endl;
cout << lua_tonumber(l, lua_gettop(l) - 7) << endl;
cout << lua_tonumber(l, lua_gettop(l) - 8) << endl;
cout << lua_tonumber(l, lua_gettop(l) - 9) << endl;
lua_pop(l, 3);/*function返回了3个值*/
cout << "\n\n" << endl;
lua_getglobal(l, "b");/*获取变量 压入栈中*/
cout <<"b=" <<lua_tonumber(l, lua_gettop(l)/*1*/ ) << endl;
lua_getglobal(l, "a");/*获取变量 压入栈中*/
cout << "a=" << lua_tonumber(l, lua_gettop(l)/*1*/) << endl;
lua_getglobal(l, "c");/*获取变量 压入栈中*/
cout << "c=" << lua_tonumber(l, lua_gettop(l)/*1*/) << endl;
lua_pop(l, 3);/*清除栈*/
cout << "top is" << lua_gettop(l) << endl;
return sum;
}
int main()
{
l = lua_open();
luaL_openlibs(l);
luaL_dofile(l, "a.lua");
//cout << get_sum(1, 2) << endl;
get_sum(1, 2);
lua_close(l);
system("pause");
return 0;
}
配套的 Lua 脚本 a.lua
C++ 这端通过 luaL_dofile(l, "a.lua") 加载的 Lua 文件内容如下,里面定义了三个全局变量和一个函数 get_sum,返回三个值。
a=10;
b=11;
c=12;
function get_sum(arg_1,arg_2)
return arg_1+arg_2,"100","200";
end