C/C++ 调用 Lua API 读取脚本变量的完整示例
在C/C++开发中嵌入Lua脚本是扩展功能的常用手段。本文演示如何通过Lua API从C端读取Lua脚本定义的全局变量。核心流程包括:创建虚拟机上下文、加载并安全执行脚本、使用lua_getglobal将变量推入虚拟栈、通过lua_tonumber转换为C类型数据,最后正确清理资源。
实现目标与准备条件
本示例的目标是在控制台应用程序(C或C++)中运行一段Lua代码,并准确获取脚本中定义的数值型全局变量rows和cols。读者需确保已配置好Lua的C头文件(如lua.h)及链接库环境。
第1步:编写测试用的 Lua 脚本
目的是定义待读取的全局变量。创建一个名为test01.lua的文件,内容如下:
function plustwo(x)
local a = 2;
return x+a;
end;
rows = 6;
cols = plustwo(rows);
该脚本定义了一个辅助函数plustwo,并将结果赋值给全局变量cols。注意Lua中默认未声明局部范围的变量为全局变量。
第2步:配置 C/C++ 项目并引入 Lua 头文件
在IDE(如VS)中新建控制台程序,必须将Lua的C接口头文件包含在extern "C"块中,以避免C++名称修饰问题。
#include <iostream>
extern "C"
{
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
}
using namespace std;
第3步:初始化虚拟机并加载脚本
创建Lua状态机(LState),打开标准库,并加载外部脚本文件。此阶段需严格检查加载和编译错误。
int main(int argc, char* argv[])
{
cout << "01_Read_Stack" << endl;
/* 创建 Lua VM */
lua_State *L = lua_open();
/* 打开必要库,根据实际需求选择开启的模块 */
luaopen_base(L);
luaopen_table(L);
luaL_openlibs(L); /* 打开所有标准库 */
luaopen_string(L);
luaopen_math(L);
int iError;
/* 加载脚本文件 */
iError = luaL_loadfile(L, "../test01.lua");
if (iError)
{
cout << "Load script FAILED!" << lua_tostring(L, -1) << endl;
lua_close(L);
return 1;
}
/* 执行加载后的 chunk */
iError = lua_pcall(L, 0, 0, 0);
if (iError)
{
cout << "pcall FAILED" << lua_tostring(L, -1) << iError << endl;
lua_close(L);
return 1;
}
// ... 后续步骤见下文
}
第4步:通过栈操作获取变量值
Lua与C交互基于“栈”。获取全局变量的步骤如下:
- 压栈:使用
lua_getglobal(L, name)获取栈顶索引。- 先调用
lua_getglobal(L, "rows")。 - 再调用
lua_getglobal(L, "cols")。 - 此时栈底在上,栈顶在下。假设栈指针为T,则
rows在T-2位置,cols在T-1位置。
- 先调用
- 类型校验:使用
lua_isnumber()确认数据类型是否符合预期。 - 取值:使用
lua_tonumber()将数值转换为C的double类型。
/* 获取全局变量 rows 和 cols 进入栈 */
lua_getglobal(L, "rows");
lua_getglobal(L, "cols");
/* 检查类型是否为数字,负数索引表示相对于栈顶的位置 */
if (!lua_isnumber(L, -2))
{
cout << "[rows] is not a number" << endl;
lua_close(L);
return 1;
}
if (!lua_isnumber(L, -1))
{
cout << "[cols] is not a number" << endl;
lua_close(L);
return 1;
}
/* 输出结果,使用 static_cast 显式转换精度 */
cout << "[rows] "
<< static_cast<int> (lua_tonumber(L, -2))
<< "\n[cols] "
<< static_cast<int> (lua_tonumber(L, -1))
<< endl;
第5步:清理栈空间并关闭虚拟机
为避免内存泄漏或栈污染,使用完毕后应弹出使用的栈元素并关闭LState。
/* 弹出最后两个元素 (rows 和 cols) */
lua_pop(L, 2);
/* 关闭 Lua VM */
lua_close(L);
return 0;
}
关键知识点解析
- 相对索引:
-1代表栈顶元素,-2代表栈顶之下一个元素。这种设计使得在中间插入或删除元素时,其他元素的索引自动调整,无需手动计算绝对索引。 - 错误处理:
luaL_loadfile负责编译脚本(静态错误),lua_pcall负责执行脚本(运行时错误)。务必对两者返回值进行检查。 - 库的开启:
lua_open仅创建空状态,需要手动luaopen_*来添加功能。生产环境中通常直接使用luaL_newstate配合luaL_openlibs以简化代码。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









