【C++/Lua联合开发】 (三) C++调用Lua

文章目录

  • 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函数

注意点:

  1. 堆栈
  2. 多线程调用(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不是函数(例如 niltable),直接 lua_pcall会失败并在栈上留下错误信息("attempt to call a ... "),应先用 lua_isfunctionlua_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
相关推荐
智者知已应修善业1 小时前
【洛谷P9975奶牛被病毒传染最少数量推导,导出多样例】2025-2-26
c语言·c++·经验分享·笔记·算法·推荐算法
Trouvaille ~1 小时前
【Linux】应用层协议设计实战(一):自定义协议与网络计算器
linux·运维·服务器·网络·c++·http·应用层协议
CSCN新手听安2 小时前
【linux】高级IO,I/O多路转接之poll,接口和原理讲解,poll版本的TCP服务器
linux·运维·服务器·c++·计算机网络·高级io·poll
CSCN新手听安2 小时前
【linux】网络基础(三)TCP服务端网络版本计算器的优化,Json的使用,服务器守护进程化daemon,重谈OSI七层模型
linux·服务器·网络·c++·tcp/ip·json
m0_736919102 小时前
C++中的委托构造函数
开发语言·c++·算法
小小小小王王王2 小时前
洛谷-P1886 【模板】单调队列 / 滑动窗口
c++·算法
历程里程碑2 小时前
Linux 库
java·linux·运维·服务器·数据结构·c++·算法
Sheep Shaun2 小时前
如何让一个进程诞生、工作、终止并等待回收?——探索Linux进程控制与Shell的诞生
linux·服务器·数据结构·c++·算法·shell·进程控制
小龙报3 小时前
【51单片机】从 0 到 1 玩转 51 蜂鸣器:分清有源无源,轻松驱动它奏响新年旋律
c语言·数据结构·c++·stm32·单片机·嵌入式硬件·51单片机
石去皿3 小时前
【嵌入式就业6】计算机组成原理与操作系统核心机制:夯实底层基础
c++·面试·嵌入式