文章目录
- C++调用Lua
-
- [1. C++调用Lua全局变量(普通类型)](#1. C++调用Lua全局变量(普通类型))
- [2. C++给Lua传递全局变量](#2. C++给Lua传递全局变量)
- [3. C++调用Lua全局变量(表)](#3. C++调用Lua全局变量(表))
- [4. C++给Lua传递全局变量表](#4. C++给Lua传递全局变量表)
- [5. C++调用Lua函数](#5. C++调用Lua函数)
-
- [5.1 基础调用](#5.1 基础调用)
- [5.2 调用Lua函数传递参数](#5.2 调用Lua函数传递参数)
- [5.3 errfunc](#5.3 errfunc)
- [5.4 返回table](#5.4 返回table)
C++调用Lua
-
全局变量访问(普通,表),函数调用(参数,返回值)
-
注意栈空间清理,防止内存泄漏
1. C++调用Lua全局变量(普通类型)
cpp
lua_getglobal(L, "width"); //取出全局变量"width"并压栈
int width = lua_tointeger(L, -1);
lua_pop(L, 1); //栈顶出栈
cout << "width: " << width << endl;
lua
width = 1920
2. C++给Lua传递全局变量
luaL_loadfile 调用前执行,设置全局变量cname:
cpp
lua_pushstring(lua, "c name value"); //压栈
lua_setglobal(lua, "cname");
lua_setglobal(L, "cname") 把栈顶的值弹出并设置为全局变量 cname(在 Lua中相当于 _G["cname"] = value)
3. C++调用Lua全局变量(表)
lua
-- main.lua
conf = {
title = "My Title",
height = 200
}
cpp
// main.cpp
lua_getglobal(L, "conf"); // [conf]
lua_getfield(L, -1, "title"); // [conf "My Title"]
cout << "title: " << lua_tostring(L, -1) << endl;
lua_pop(L, 1); // [conf]
lua_getfield(L, -1, "height"); [conf 200]
cout << "height: " << lua_tointeger(L, -1) << endl;
lua_pop(L, 1); // [conf]
4. C++给Lua传递全局变量表
cpp
lua_newtable(L); //[..., table]
lua_pushstring(L, "skan"); // [..., table, "skan"]
//把栈顶值作为value,弹出它并设置索引-2处表的字段name,等价于table["name"]=value
lua_setfield(L, -2, "name"); // [..., table]
lua_pushinteger(L, 42);
lua_setfield(L, -2, "age");
lua_setglobal(L, "person");
lua
-- main.lua
print("person name: " .. person.name)
print("person age: " .. person.age)
5. C++调用Lua函数
注意点:
- 堆栈
- 多线程调用(
dispatch的方式)
5.1 基础调用
lua
function lua_event()
print("Event triggered")
end
cpp
lua_getglobal(L, "lua_event");
if (!lua_isfunction(L, -1)) {
// 不是函数:弹出并忽略
lua_pop(L, 1); // 栈恢复
}
else {
int ret = lua_pcall(L, 0, 0, 0); // 弹出函数并调用
if (ret != LUA_OK) {
const char* err = lua_tostring(L, -1); // 栈顶是错误信息
printf("call event error: %s\n", err);
lua_pop(L, 1); // 弹出错误信息
}
}
-
lua_getglobal(L, "lua_event"):把全局变量lua_event的值压入栈顶(不弹出任何东西)。- 调用前(假设栈为空):[]
- 调用后:[ lua_event_value ](栈顶索引 -1)
-
lua_pcall(lua_State *L, int nargs, int nresults, int errfunc)的行为:- 要求栈顶 是一个可调用值(
function)。lua_pcall会弹出该函数和传入的参数 (此处nargs=0),在保护模式下调用它。 - 成功返回(
ret == LUA_OK):根据nresults=0,不会把函数的返回值压回栈,最终栈回到调用前的状态(即如果之前只有函数,则变为空栈)。 - 调用前:[ function ] → 调用后(成功):[]
- 失败返回(
ret != LUA_OK):lua_pcall在栈顶压入错误信息(error message),并返回错误码。- 调用后(出错):[ error_msg ]
- 要求栈顶 是一个可调用值(
-
如果
lua_event不是函数(例如nil或table),直接lua_pcall会失败并在栈上留下错误信息("attempt to call a ... "),应先用lua_isfunction或lua_type检查
5.2 调用Lua函数传递参数
lua
function lua_event(e1)
print("Event triggered")
print(e1)
return "test lua_event"
end
cpp
lua_getglobal(L, "lua_event");
if (!lua_isfunction(L, -1)) {
// 不是函数:弹出并忽略
lua_pop(L, 1); // 栈恢复
}
else {
lua_pushstring(L, "hello from C");
lua_newtable(L);
lua_pushstring(L, "skan");
lua_setfield(L, -2, "name");
int ret = lua_pcall(L, 2, 1, errfunc_pos); // 弹出函数并调用
if (ret != LUA_OK) {
const char* err = lua_tostring(L, -1); // 栈顶是错误信息
printf("call event error: %s\n", err);
lua_pop(L, 1); // 弹出错误信息
}
else {
printf("lua return: %s\n", lua_tostring(L, -1));
lua_pop(L, 1);
}
}
5.3 errfunc
lua
-- main.lua
function my_error_handler(err)
return "Custom error: " .. tostring(err)
endnd
c
// ...existing code...
int errfunc_pos = lua_gettop(L) + 1;
lua_getglobal(L, "my_error_handler"); // 压入错误处理函数,假设索引为 1
// 栈: [..., my_error_handler]
lua_getglobal(L, "lua_event"); // 压入要调用的函数
lua_pushstring(L, "hello from C"); // 参数
// 栈: [..., my_error_handler, lua_event, "hello from C"]
int ret = lua_pcall(L, 1, 1, errfunc_pos);
if (ret != LUA_OK) {
const char* err = lua_tostring(L, -1); // 栈顶是 errfunc 返回的字符串
printf("Handled error: %s\n", err);
lua_pop(L, 1);
} else {
printf("Success: %s\n", lua_tostring(L, -1));
lua_pop(L, 1);
}
lua_pop(L, 1); // errfunc出栈
5.4 返回table
cpp
lua_pushstring(L, "hello from C");
lua_newtable(L);
lua_pushstring(L, "skan");
lua_setfield(L, -2, "name");
int ret = lua_pcall(L, 2, 1, errfunc_pos); // 弹出函数lua_event("hello from C", tab1)并调用
if (ret != LUA_OK) {
const char* err = lua_tostring(L, -1); // 栈顶是错误信息
printf("call event error: %s\n", err);
lua_pop(L, 1); // 弹出错误信息
}
else {
lua_getfield(L, -1, "result");
if (lua_isstring(L, -1))
cout << "result: " << lua_tostring(L, -1) << endl;
else if (lua_isnumber(L, -1))
cout << "result: " << lua_tonumber(L, -1) << endl;
else
cout << "result: " << lua_typename(L, lua_type(L, -1)) << endl;
lua_pop(L, 2);
}
lua
function lua_event(e1, tb2)
print("Event triggered")
print(e1)
print(tb2.name)
return {result = "success"}
end