C++与 Lua的交互

作者:kebeiovo日期:2026/6/1

适用场景:游戏服务端、客户端热更新、业务逻辑解耦、C++高性能底层+Lua灵活业务架构

核心定位:C++负责高性能底层(网络、内存池、epoll、计算),Lua负责业务逻辑、配置解析、热更新,二者结合是游戏行业主流生产方案。

一、交互原理

1.1 交互核心载体

所有C++与Lua的交互,全部围绕 Lua虚拟机(lua_State) 实现;

Lua 是编译型 + 解释型的嵌入式脚本语言,自身不依赖独立进程运行,它的代码最终交由 Lua 虚拟机(Lua VM) 执行。

Lua 虚拟机本质是一套运行在宿主程序(C++ 程序)内部的软件指令机,负责解析、执行 Lua 代码、管理内存、维护运行时环境。 我们代码里的 lua_State* L一个 lua_State 就代表一个独立的 Lua 虚拟机实例

C++ 是宿主,Lua 虚拟机跑在 C++ 进程里,所有 Lua 代码、数据、函数调用、GC 全由它托管。

核心机制:虚拟栈

所有数据传递、函数传参、返回值、对象映射,都遵循 压栈-出栈 规则,栈是二者唯一的通信介质。

1.2 虚拟栈核心规则

  • 栈结构:后进先出,所有Lua数据(数字、字符串、table、函数、nil、userdata)均存储在栈上
  • 索引规则:正数索引从栈底开始,负数索引从栈顶开始(-1固定代表栈顶元素
  • 核心原则:栈必须平衡,操作后及时清理,避免栈溢出、数据错乱

1.3 环境配置基础

C++调用Lua API必须兼容C语言规则,防止C++名字改编导致注册失败,固定引入方式:

1extern "C" {
2#include "lua.h"
3#include "lualib.h"
4#include "lauxlib.h"
5}

二、四大交互场景

2.1 C++ 读取执行Lua脚本 & 全局变量

实现流程

创建虚拟机 → 加载标准库 → 执行Lua脚本 → 栈读取全局变量 → 弹出栈数据 → 关闭虚拟机

完整实操代码

Lua测试脚本(test.lua):

1g_num = 666
2g_str = "C++ Lua交互测试"
3g_flag = true

C++读取代码:

1#include <iostream>
2extern "C" {
3#include "lua.h"
4#include "lualib.h"
5#include "lauxlib.h"
6}
7
8int main() {
9    // 1. 创建Lua虚拟机
10    lua_State* L = luaL_newstate();
11    // 加载Lua标准库(字符串、表、IO等)
12    luaL_openlibs(L);
13
14    // 2. 执行外部Lua脚本
15    if (luaL_dofile(L, "test.lua") != LUA_OK) {
16        std::cout << "脚本执行失败:" << lua_tostring(L, -1) << std::endl;
17        lua_pop(L, 1);
18        lua_close(L);
19        return -1;
20    }
21
22    // 3. 读取全局变量(压栈→取值→出栈)
23    lua_getglobal(L, "g_num");
24    double num = lua_tonumber(L, -1);
25    lua_pop(L, 1);
26
27    lua_getglobal(L, "g_str");
28    const char* str = lua_tostring(L, -1);
29    lua_pop(L, 1);
30
31    std::cout << "数值:" << num << " 字符串:" << str << std::endl;
32
33    // 4. 关闭虚拟机
34    lua_close(L);
35    return 0;
36}

2.2 C++ 调用Lua函数

实现流程

加载脚本 → 压入Lua函数 → 压入函数参数 → lua_pcall执行调用 → 栈读取返回值 → 清理栈

实操示例

Lua函数:

1function add(a, b)
2    return a + b, "调用成功"
3end

C++调用逻辑:

1// 压入Lua函数
2lua_getglobal(L, "add");
3// 压入参数
4lua_pushnumber(L, 10);
5lua_pushnumber(L, 20);
6
7// 调用函数:2个参数,2个返回值
8if (lua_pcall(L, 2, 2, 0) != LUA_OK) {
9    std::cout << "函数调用失败:" << lua_tostring(L, -1) << std::endl;
10    lua_pop(L, 1);
11    return -1;
12}
13
14// 读取返回值
15double res = lua_tonumber(L, -2);
16const char* msg = lua_tostring(L, -1);
17lua_pop(L, 2);
18
19std::cout << "计算结果:" << res << " 状态:" << msg << std::endl;

2.3 Lua 调用C++函数(热更新)

强制规则:被Lua调用的C++函数,必须遵循固定C函数签名,禁止C++类成员函数直接调用

1typedef int (*lua_CFunction)(lua_State* L);
2// 返回值:压入栈的返回值个数
3// 参数:全部从Lua虚拟栈读取

完整注册+调用示例

1// 1. 定义可被Lua调用的C++函数
2int lua_cpp_add(lua_State* L) {
3    // 从栈读取Lua传入的参数
4    double a = lua_tonumber(L, 1);
5    double b = lua_tonumber(L, 2);
6    // 结果压栈,作为返回值
7    lua_pushnumber(L, a + b);
8    // 返回1个返回值
9    return 1;
10}
11
12// 2. 函数注册表
13static const luaL_Reg funcReg[] = {
14    {"cpp_add", lua_cpp_add},
15    {nullptr, nullptr} // 结束标记
16};
17
18// 3. 注册函数到Lua全局环境
19void registerCppFunc(lua_State* L) {
20    luaL_newlib(L, funcReg);
21    lua_setglobal(L, "CppLib");
22}

Lua调用代码:

1local ret = CppLib.cpp_add(100, 200)
2print("Lua调用C++结果:", ret)

2.4 C++与Lua Table表交互

Table是Lua核心数据结构,用于配置存储、对象数据传输,支持C++读写双向交互。

1、C++读取Lua Table

Lua表定义:

role = {id = 1001, name = "玩家1", hp = 1000}

C++读取逻辑:

1lua_getglobal(L, "role"); // table压栈
2lua_getfield(L, -1, "id");
3int id = lua_tointeger(L, -1);
4lua_pop(L, 1);
5
6lua_getfield(L, -1, "name");
7const char* name = lua_tostring(L, -1);
8lua_pop(L, 1);
9
10lua_pop(L, 1); // 清理table栈

2、C++创建Lua Table

1lua_newtable(L); // 新建空表
2
3// 键值对入表
4lua_pushstring(L, "monster_hp");
5lua_pushnumber(L, 888);
6lua_settable(L, -3);
7
8// 注册为Lua全局变量
9lua_setglobal(L, "monster");

三、C++对象映射Lua(userdata)

业务核心需求:将C++类对象暴露给Lua调用,通过 userdata+元表metatable 实现,是游戏业务开发的核心用法。

3.1 核心原理

  • userdata:Lua自定义数据类型,用于存储C++对象指针
  • metatable:元表,为userdata绑定成员方法、GC回收机制
  • __gc元方法:解决C++对象内存泄漏,LuaGC时自动delete堆对象

3.2 极简完整示例

1// C++业务类
2class Player {
3public:
4    int hp = 100;
5    void hurt(int dmg) { hp -= dmg; }
6};
7
8// Lua调用对象受伤方法
9int player_hurt(lua_State* L) {
10    Player* p = *(Player**)lua_touserdata(L, 1);
11    int dmg = lua_tointeger(L, 2);
12    p->hurt(dmg);
13    return 0;
14}
15
16// Lua获取对象血量
17int player_gethp(lua_State* L) {
18    Player* p = *(Player**)lua_touserdata(L, 1);
19    lua_pushinteger(L, p->hp);
20    return 1;
21}
22
23// 注册对象元表
24void regPlayerMeta(lua_State* L) {
25    luaL_newmetatable(L, "PlayerMeta");
26    luaL_Reg reg[] = {
27        {"hurt", player_hurt},
28        {"getHp", player_gethp},
29        {nullptr, nullptr}
30    };
31    luaL_setfuncs(L, reg, 0);
32    lua_pop(L, 1);
33}
34
35// 创建C++对象返回给Lua
36int create_player(lua_State* L) {
37    Player* p = new Player();
38    *(Player**)lua_newuserdata(L, sizeof(Player*)) = p;
39    // 绑定元表
40    luaL_getmetatable(L, "PlayerMeta");
41    lua_setmetatable(L, -2);
42    return 1;
43}

Lua业务调用:

1local player = CppLib.create_player()
2player:hurt(30)
3print("剩余血量:", player:getHp())

四、游戏架构&热更新原理

4.1 C+++Lua分层架构

  • C++底层:epoll网络、内存池/对象池、定时器、协议解析、高性能计算、底层引擎
  • Lua业务层:角色逻辑、玩法流程、配置读取、协议处理、UI逻辑

交互流程:网络消息C++收包 → 转发Lua回调 → Lua执行业务 → 调用C++底层接口回包

4.2 Lua热更新核心原理

  1. 服务运行中,重新加载修改后的Lua脚本
  2. 新脚本覆盖全局函数、表数据
  3. 无需重启C++主程序,实现业务逻辑秒级更新

这是游戏行业选用Lua做业务脚本的核心原因


C++与 Lua的交互》 是转载文章,点击查看原文


相关推荐


营销数据分析:如何利用IP归属地识别和规避虚假流量
TechWayfarer2026/5/12

一、流量作弊:程序化广告的隐形黑洞 程序化广告已成为数字营销的主流投放方式,但伴随着海量流量而来的,是日益猖獗的虚假流量产业链。根据中国互联网络信息中心发布的数据,截至2025年6月,我国网民规模已达11.23亿人,互联网普及率达79.7%。庞大的用户基数为黑灰产提供了可乘之机。 在程序化广告交易中,虚假流量问题尤为突出。据行业实测数据显示,某DSP平台日均处理超过50亿次广告竞价请求,其中约30%的流量来自数据中心IP或代理IP,这些流量中真正产生转化的不足0.5%,却消耗了平台近四分之一


03ab-PyTorch安装教程 📚
郑恩赐2026/5/3

03ab-PyTorch安装教程 📚 章节阅读路线图 🗺️ flowchart LR A["1. 概述"]:::concept --> B["2. 安装前准备"]:::setup B --> C["3. CPU版本安装"]:::cpu C --> D["4. GPU版本安装"]:::gpu D --> E["5. 验证安装"]:::verify classDef concept fill:#e3f2fd,stroke:#1565c0 clas


廉价 VPS 越来越少,不是没活动,是真的没货了
小墨同学boy2026/4/24

很多小伙伴都来问我什么时候 DMIT 会有活动,特价款什么时候补货,其实我自己都不知道,甚至别说活动款,连很多廉价 VPS 厂商都缺货了。 今天早上一起来,本来开开心心的看监控站点的内容,结果发现 Racknerd 的特价套餐基本全线缺货,这还不是第一次了。前段时间 CloudCone 的优惠套餐挂着缺货,这两家向来是廉价 VPS 圈的地板价代表,现在同时没货。翻了一圈,我才意识到不是商家不想做活动,是真的没货可卖。 不是没活动,是货快没了 不知道有没有 mjj 和我一样,过去两三个月一直盯


整洁架构三连问:是什么,怎么做,为什么要用
暖阳_2026/4/15

整洁架构问答 Q1:什么是整洁架构? 由 Robert C. Martin(Uncle Bob)提出,核心思想:业务逻辑独立于框架、UI、数据库等外部细节,依赖关系只能从外层指向内层。 四层结构 ┌─────────────────────────────────┐ │ Frameworks & Drivers │ ← Web、数据库、UI(最易变) │ ┌─────────────────────────┐ │ │ │ Interface Adapters


Flutter 框架跨平台鸿蒙开发 - 跟生活有关的心情日记应用开发
小雨天気.2026/4/7

欢迎加入开源鸿蒙跨平台社区: https://openharmonycrossplatform.csdn.net 一、项目概述 运行效果图 1.1 应用简介 心情日记是一款专注于情感记录与追踪的移动应用,为用户提供一个私密、便捷的空间记录每日心情变化。在快节奏的现代生活中,人们常常忽略了对自身情绪的关注与觉察,本应用帮助用户追踪情绪轨迹,从而更好地了解自己、关爱自己。 应用支持八种心情类型选择,配以表情符号与主题色彩,让情绪表达更加直观生动。日记撰写支持标题、内容、


第12章 I2C通信协议全解:底层时序、主从机通信与AT24C02、MPU6050传感器实战
是翔仔呐2026/3/29

前言 上一章我们通过硬件I2C完成了OLED屏的驱动开发,实现了字符与图像的显示,但未深入拆解I2C协议的底层逻辑。I2C是工业嵌入式开发中最常用的低速串行总线,是传感器、存储芯片、显示外设的核心通信方式。对应51单片机开发,我们通常通过软件翻转IO口模拟I2C时序,存在时序精度差、CPU占用率100%、多从机兼容性差、无硬件错误处理的痛点;而STM32内置硬件I2C控制器,可自动生成标准时序、处理应答机制、支持DMA高速传输,完美适配工业场景多设备、高稳定性的通信需求。新手入门I2C普遍面临三


【Kotlin】 数据流完全指南:冷流、热流与 Android 实战
idealzouhu2026/3/21

文章目录 一、数据流简介1.1 Kotlin 数据流概述1.2 核心特性1.3 Flow 的基本组件 二、数据流的使用方法2.1 正向流2.1.1 创建数据流2.1.2 修改数据流2.1.3 收集数据流 2.2 反向流2.2.1 创建数据流2.2.2 修改并收集数据流 2.3 数据流在 Jetpack 中的应用场景 三、数据流的行为模式3.1 冷流(Cold Flow)3.1.1 什么是冷流3.1.2 为什么 Kotlin 默认使用冷流 3.2 热流(Hot


特高压输变电工程全生命周期BIM+GIS数字化管理平台:重塑能源动脉的数字基石(WORD)
无忧智库2026/3/13

引言:能源互联网时代的数字化觉醒 在“双碳”目标的宏大叙事下,中国能源结构正经历着前所未有的深刻变革。作为能源配置的“大动脉”,特高压输变电工程以其输送容量大、距离远、损耗低的技术优势,成为了构建新型电力系统的核心骨架。然而,随着工程规模的指数级增长和地理环境的日益复杂,传统的管理模式正面临着严峻的挑战。设计阶段的各专业协同困难、施工阶段的进度与质量管控盲区、运维阶段的海量数据孤岛,如同一个个隐形的枷锁,制约着电网建设效率的提升和全生命周期价值的释放。 当物理世界的铁塔银线不断向天际延伸时,数字


windows下配置Qt arm32交叉编译环境
itas1092026/3/5

windows下配置Qt arm32交叉编译环境 环境: 系统:windows 11 Qt: 5.12.12(2021-11-25) 本地编译器:mingw73 64(2018-04-25) 交叉编译器: gcc-linaro-7.3.1-2018.05-i686-mingw32_arm-linux-gnueabi perl: strawberry perl 5.22.1(2016-01-07) python: 3.8.10(2021-05-03) 1. 安装Qt MinGW Perl Pyt


告别死板流程:OpenSpec OPSX 如何重塑 SDD 开发工作流
fundroid2026/2/25

引言:SDD 与 OpenSpec 规范驱动开发(SDD)是什么? 近两年,AI 编码助手已经能“听懂人话”,从一段自然语言描述里生成大段代码。但很多团队也发现:如果需求只是散落在聊天记录里、脑补在每个人的心里,AI 很容易“发挥过度”——代码写出来了,却不是你真正想要的系统行为。 规范驱动开发(Spec-Driven Development,SDD)试图解决的,就是这个问题。它把规范(spec)而不是代码当成系统的“单一事实来源”:先用结构化、机器可读的方式,把系统应该做什么、有哪些边界和不变

首页编辑器站点地图

本站内容在 CC BY-SA 4.0 协议下发布

Copyright © 2026 聚合阅读