当前位置: 首页 > news >正文

【C++/Lua联合开发】 (二) Lua调用C++函数

文章目录

  • Lua调用C++
    • 1. Lua与C++交互次序
    • 2. Lua栈的访问下标
    • 3. 示例
      • 3.1 无参数无返回值
      • 3.2 普通参数
      • 3.3 数组参数
      • 3.4 表类型参数
        • 3.4.1 lua_next(L, 1)遍历表:
        • 3.4.2 lua_getfield(L, 1, "name")获取表中内容
      • 3.5 有返回值的函数

Lua调用C++

  • 函数调用

  • 参数传递

  • 返回值获取

1. Lua与C++交互次序

交互次序

2. Lua栈的访问下标

栈

3. 示例

3.1 无参数无返回值

int CTest(lua_State* L) {printf("int CTest\n");return 0;   //返回值个数
}lua_register(L, "CTest1", CTest);
CTest1()

3.2 普通参数

int CTest(lua_State* L) {cout << "int CTest" << endl;size_t sz = 0;const char* arg1 = lua_tolstring(L, 1, &sz); //从栈底开始取元素并出栈int arg2 = lua_tonumber(L, 2);cout << "arg1: " << arg1 << ", size: " << sz << ", arg2: " << arg2 << endl;return 0;
}lua_register(L, "CTest2", CTest);
CTest2("hello skan", 123)

3.3 数组参数

int CTestArray(lua_State* L) { cout << "int CTestArray" << endl;if (!lua_istable(L, 1)) {cout << "arg1 is not a table" << endl;return 0;}//取得栈上指定索引处对象的“长度”(字符串长度或表的长度)
#if LUA_VERSION_NUM >= 502size_t sz = lua_rawlen(L, 1);
#elsesize_t sz = lua_objlen(L, 1);
#endifcout << "array size: " << sz << endl;for (size_t i = 1; i <= sz; ++i) {lua_pushinteger(L, i);lua_gettable(L, 1);cout << "element " << i << ": " << lua_tostring(L, -1) << endl;lua_pop(L, 1);}return 0;
}
1.调用前准备: 必须手动将两样东西放到 Lua 栈上:- 要查询的 **表(table)**- 要使用的 **键(key)** 2. 栈状态 (调用前): 假设你要执行 `value = my_table[my_key]`。你需要先将 `my_table` 和 `my_key` 压栈。`my_key` 必须在栈顶。栈底 | ... | my_table (在索引 index 处) | ... |  my_key (在栈顶, -1) |3. 执行 lua_gettable(L, index):函数会查看 index 参数,找到 my_table。它会弹出 (pop) 栈顶的 my_key。它在 my_table 中查找 my_key 对应的 value。最后,它将查找到的 value 压入 (push) 栈顶。4. 栈状态 (调用后): my_key 被 value 替换掉了。
栈底 | ... | my_table (在索引 index 处) | ... | value (在栈顶, -1) |

3.4 表类型参数

3.4.1 lua_next(L, 1)遍历表:

lua_next(L, 1)

  1. 从栈顶弹出一个key
  2. 从栈指定位置的table里取一对key-value, 先将key入栈再将value入栈
  3. 如果第2步成功,返回非0值,否则返回0,并且不向栈中压入任何值。
// Lua C 函数,用于遍历和分析 Lua 表的内容
// 参数: L - Lua 状态机
// 返回值: 0 (不向 Lua 返回任何值)
// 调用示例 (Lua): CTestTable({name="test", age=18, [1]="first"})
int CTestTable(lua_State* L) { cout << "int CTestTable" << endl;// 初始状态: [table]  (假设调用时传入一个表作为第一个参数)// 检查第一个参数是否为表类型if (!lua_istable(L, 1)) {cout << "arg1 is not a table" << endl;return 0;}// 当前栈: [table]// 获取表的"数组部分"长度(连续整数索引 1, 2, 3... 的元素个数)// 注意: 这只统计数组部分,不包括哈希部分(字符串键等)
#if LUA_VERSION_NUM >= 502size_t sz = lua_rawlen(L, 1);    // Lua 5.2+ 使用 lua_rawlen
#elsesize_t sz = lua_objlen(L, 1);    // Lua 5.1 使用 lua_objlen
#endifcout << "table size: " << sz << endl;// 当前栈: [table]// 压入 nil 作为初始键,用于开始遍历表lua_pushnil(L);// 当前栈: [table nil]// lua_next(L, 1) 的工作原理:// 1. 弹出栈顶的键 (第一次是 nil)// 2. 找到表中的下一个键值对// 3. 将键和值依次压入栈// 4. 如果还有下一对,返回非 0;遍历结束返回 0while (lua_next(L, 1) != 0) {// 第一次迭代: [table key1 value1]// 第二次迭代: [table key2 value2]// ...// 注意: 索引 -2 是键,索引 -1 是值cout << "key: " << lua_tostring(L, -2) << ", value: ";// 根据值的类型输出不同的内容if (lua_isstring(L, -1))cout << lua_tostring(L, -1);else if (lua_isnumber(L, -1))cout << lua_tonumber(L, -1);elsecout << lua_typename(L, lua_type(L, -1));cout << endl;// 当前栈: [table key value]// 弹出值,保留键给下一次 lua_next 使用lua_pop(L, 1);// 当前栈: [table key]// 循环继续,lua_next 会:// 1. 弹出当前的 key// 2. 压入下一个 key 和 value (如果有)}// 遍历结束后,lua_next 返回 0 并弹出了最后一个键// 最终栈状态: [table]return 0;  // 不向 Lua 返回任何值,栈保持 [table] 状态
}
-- main.lua
local tab = {"001", "002", "003"}
CTestTable(tab)
3.4.2 lua_getfield(L, 1, “name”)获取表中内容
static struct script_ctx *get_ctx(lua_State *L) {// 初始栈: [...]lua_getfield(L, LUA_REGISTRYINDEX, "ctx");// 从注册表中获取 "ctx" 字段// 堆栈: [... ctx_userdata]struct script_ctx *ctx = lua_touserdata(L, -1);lua_pop(L, 1);// 堆栈: [...]mp_assert(ctx);return ctx;
}

3.5 有返回值的函数

  1. 返回普通类型对象
    lua_pushstring(l, str) lua_pushnumber(l, 123)
// main.cpp
int CTestRet(lua_State* L) { lua_pushstring(L, "return skan");return 1;   //取栈顶的第一个元素作为返回值
}
-- main.lua
local ret = CTestRet();
print("ret from CTestRet:" .. ret);
  1. 返回表对象
// main.cpp
int CTestRet(lua_State* L) { lua_newtable(L);   // 创建一个新表,栈: [..., table]// 字符串字段: table.name = "skan"lua_pushstring(L, "skan");   // 栈: [..., table, "skan"]lua_setfield(L, -2, "name"); // 弹出 "skan",设置 table["name"]="skan",表仍在栈上// 数值字段: table.age = 42lua_pushinteger(L, 42);      // 栈: [..., table, 42]lua_setfield(L, -2, "age");  // 弹出 42,设置 table["age"]=42// 布尔字段: table.online = truelua_pushboolean(L, 1);       // 栈: [..., table, true]lua_setfield(L, -2, "online");// 弹出 true,设置 table["online"]=true// 作为数组部分插入: table[1] = "first", table[2] = "second"lua_pushstring(L, "first");  lua_rawseti(L, -2, 1);       // 弹出 "first",设置 table[1]="first"lua_pushstring(L, "second");lua_rawseti(L, -2, 2);       // 弹出 "second",设置 table[2]="second"return 1; // 返回栈顶的表(table 必须位于栈顶)
}
-- main.lua
local ret = CTestRet();if ret == nil thenprint("ret is nil")return
endif(type(ret) == "table") thenfor key, value in pairs(ret) doprint("Key: " .. key .. ", Value: " .. value)end
end
http://www.dtcms.com/a/499123.html

相关文章:

  • 基于Simulink的混动汽车模型建模与仿真,包含发动机管理,电机,电池管理以及混动汽车物理模型等
  • 网站备案都需要什么网站群项目建设实施进度计划
  • 数据库的事务和索引
  • W5500 esp32 micropython 驱动测试 网线直连电脑静态IP设置
  • 1panel docker开启swap内存
  • 动态规划的“降维”艺术:二维矩阵中的建筑奇迹——最大矩形
  • switch语句在汇编层面的几种优化方式 ,为什么能进行优化
  • Apache Spark算法开发指导-特征转换VectorIndexer
  • 企业网站的高跳出率应该如何解决广州物流网站开发
  • Docker 与 K8s 网络模型全解析
  • 【算法与数据结构】拓扑排序实战(栈+邻接表+环判断,附可运行代码)
  • AWS Elastic Load Balancing(ELB)—— 多站点负载均衡的正确打开方式
  • 如何用域名建网站主流建站公司
  • 企业网站模板源代码jz做网站
  • 深入 Spring 内核:解密 15 种设计模式的实战应用与底层实现
  • 【S32K3XX系列MCAL配置-第一节开发环境搭建】
  • 中矿资源的财报估值分析
  • 网站关键词优化方案分为几个步骤嘉兴微信网站建设
  • stm32驱动LTC2494详解
  • AI写作赋能SEO:用提示词打造从标题到发布的全流程优化策略
  • PVT(Pyramid Vision Transformer):金字塔结构,适合检测/分割
  • SSRF 漏洞深度剖析:从原理到实战
  • Python第十八节 命名空间作用域详细介绍及注意事项
  • 网站怎么做跳转链接域名备案要多少钱
  • 哪个网站查公司信息比较准网站设计像素
  • mq和rocketmq
  • AI搜索自由:Perplexica+cpolar构建你的私人知识引擎
  • C++基础:(十五)queue的深度解析和模拟实现
  • VSR 项目解析
  • 软件工程新纪元:AI协同编程架构师的修养与使命