Lua与C交互API接口总结
Lua与C交互
- 1. 常见Lua相关的C API
- 压入元素
- 查询元素
- 获取元素
- 检查元素
- 栈的相关数据操作
- 2. C调用Lua
- 核心调用函数
- 示例
- 3. Lua调用C
- 1. C函数注册到Lua(lua_register)
- 示例
- 2. 批量注册(luaL_Reg)
- 示例
1. 常见Lua相关的C API
压入元素
// cpp
void lua_pushnil(lua_State *L);
void lua_pushboolean(lua_State *L, int bool);
void lua_pushnumber(lua_State *L, lua_Number n);
void lua_pushinteger(lua_State *L, lua_Integer n);
void lua_pushlstring(lua_State *L, const char* s, size_t len);
void lua_pushstring(lua_State *L, const char* s);
void lua_pushfunction(lua_State *L, lua_CFunction fn);
查询元素
// cpp
int lua_is***(lua_State *L, int index); // 检查lua数据类型 nil number string table等// lua_type 函数是 Lua C API 中用于获取指定索引处的值的类型的函数。它返回一个表示值类型的整数,并且不会改变堆栈上的内容。
/* 如果索引处的值存在,则返回该值的类型,以整数形式表示。返回值为以下预定义的常量之一:
LUA_TNIL:空值。
LUA_TBOOLEAN:布尔值。
LUA_TLIGHTUSERDATA:轻量用户数据。
LUA_TNUMBER:数字。
LUA_TSTRING:字符串。
LUA_TTABLE:表。
LUA_TFUNCTION:函数。
LUA_TUSERDATA:用户数据。
LUA_TTHREAD:线程(协程)。
如果索引处的值不存在,则返回 LUA_TNONE。
*/
int lua_type(lua_State *L, int index);
获取元素
// cpp
// to* 相关操作并不会改变lua栈,只是从栈中index出取值并转成c变量类型int lua_toboolean(lua_State *L, int index); // 从栈中获取bool值const char *lua_tostring(lua_State *L, int index);// len:用于存储字符串长度的指针(可选参数)。如果为 NULL,则不返回字符串长度
const char *lua_tolstring(lua_State *L, int index, size_t *len);// lua_Integer 通常在 Lua 的头文件(如 lua.h 或 luaconf.h)中定义
// typedef long long lua_Integer
lua_Integer lua_tointeger(lua_State *L, int index);// lua_Number 通常在 Lua 的头文件(如 lua.h 或 luaconf.h)中定义
// typedef double lua_Number;
lua_Number lua_tonumber(lua_State *L, int index);int lua_toboolean(lua_State *L, int index);
检查元素
// cpp
int luaL_checkinteger(lua_State *L, int arg); lua_Number luaL_checknumber(lua_State *L, int arg);const char* luaL_checkstring(lua_State *L, int arg);int luaL_checkboolean(lua_State *L, int arg);// t:要检查的类型,在 Lua 中表示为预定义的宏,例如 LUA_TNUMBER、LUA_TSTRING 等。
void luaL_checktype(lua_State *L, int arg, int t);
栈的相关数据操作
// cpp
lua_pop(lua_State *L, int n); // 弹出栈顶的 n 个值。lua_gettop(lua_State *L); // 返回堆栈的栈顶索引(但不修改堆栈)。lua_settop(lua_State *L, int index);// 修改栈元素数量,减小栈则会丢弃多余部分元素,增大会push nil值lua_remove(lua_State *L, int index); // 移除指定索引处的值,并将上面的所有值下移。// 用于将指定索引处的值复制到堆栈顶部。它不会删除原始值,而是将其复制一份并推入堆栈。
void lua_pushvalue(lua_State *L, int index);// 用于将栈顶的值弹出,并将其设置为lua的全局变量
void lua_setglobal(lua_State *L, const char *name);// 用于将lua全局变量的值推入堆栈
void lua_getglobal(lua_State *L, const char *name);// 用于将栈顶的值弹出,并将其设置为index处的表中指定字段的值
/* lua_setfield 从栈顶弹出一个值,并将其设置为表中指定字段的值。
这个操作相当于在 Lua 中执行 t[k] = value,其中 t 是栈中索引为 index 的表,k 是字段名,value 是栈顶的值。*/
void lua_setfield(lua_State *L, int index, const char *k);// 用于从指定索引处的表中获取一个字段的值,并将其推入堆栈
void lua_getfield(lua_State *L, int index, const char *k);
2. C调用Lua
核心调用函数
void lua_call(lua_State *L, int nargs, int nresults); // 相对lua_pcall来说至少了错误处理函数int lua_pcall(lua_State *L, int nargs, int nresults, int errfunc);
/* lua_State *L:指向 Lua 状态的指针。
int nargs:要传递给 Lua 函数的参数数量。
int nresults:Lua 函数预期返回的结果数量。
int errfunc:错误处理函数在堆栈中的索引。通常为 0,表示没有错误处理函数。0:调用成功。
非零值:调用失败,对应于不同的错误代码,例如 LUA_ERRRUN、LUA_ERRMEM、LUA_ERRERR 等。lua_call和lua_pcall 执行时在堆栈上进行以下操作:
从栈顶开始,依次向下计算 nargs 个元素,这些元素表示传递给函数的参数,会依次弹出这几个参数。
在参数之后的那个元素应该是要调用的函数。
弹出函数本身,调用函数,并期望 nresults 个返回值,压入 nresults 个返回值。
*/
示例
-- Lua
function add(a, b)return a + b
end
// cpp
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#include <stdio.h>int main() {lua_State *L = luaL_newstate(); // 创建新的 Lua 状态luaL_openlibs(L); // 打开标准库if (luaL_dofile(L, "script.lua")) { // 加载并执行 Lua 脚本fprintf(stderr, "Failed to load script: %s\n", lua_tostring(L, -1));return 1;}lua_getglobal(L, "add"); // 将全局函数 "add" 压入堆栈if (!lua_isfunction(L, -1)) {fprintf(stderr, "'add' is not a function\n");return 1;}lua_pushnumber(L, 10); // 压入第一个参数lua_pushnumber(L, 20); // 压入第二个参数// lua_call(L, 2, 1); // 调用函数,传递 2 个参数,期望 1 个结果if (lua_pcall(L, 2, 1, 0) != 0) { // 调用函数,传递 2 个参数,期望 1 个结果fprintf(stderr, "Error calling 'add': %s\n", lua_tostring(L, -1));return 1;}if (lua_isnumber(L, -1)) {double result = lua_tonumber(L, -1);printf("Result: %f\n", result); // 打印结果} else {fprintf(stderr, "Function 'add' did not return a number\n");}lua_pop(L, 1); // 从堆栈中移除结果lua_close(L); // 关闭 Lua 状态return 0;
}
3. Lua调用C
Lua调用C函数时,必须遵守int FunctionName(lua_State *L)类型去定义并实现,其中int返回值表示参数个数。当每个Lua调用C函数时,会自动在内部维护一个私有局部栈,因此我们去参数时直接从1取就可以,且在调用时与结束调用时无需考虑栈的清理问题。
1. C函数注册到Lua(lua_register)
// lua_register 是 Lua C API 中的一个宏,用于将 C 函数注册为 Lua 全局函数/* 这个宏实际上是 lua_pushcfunction 和 lua_setglobal 两个函数的组合:
lua_pushcfunction(L, f):将 C 函数 f 压入 Lua 堆栈。
lua_setglobal(L, n):将堆栈顶部的值(即刚刚压入的 C 函数 f)设置为全局变量 n。*/#define lua_register(L, n, f) \(lua_pushcfunction(L, (f)), lua_setglobal(L, (n)))
示例
-- script.lua
local result = add(10, 20)
print("Result of add(10, 20):", result)
// cpp
#include <iostream>
#include <lua.hpp>// C++ 函数
int add(lua_State* L) {int a = luaL_checkinteger(L, 1);int b = luaL_checkinteger(L, 2);lua_pushinteger(L, a + b);return 1;
}// 将 C++ 函数注册到 Lua
void register_functions(lua_State* L) {lua_register(L, "add", add);
}int main() {lua_State* L = luaL_newstate(); // 创建新的 Lua 状态luaL_openlibs(L); // 打开标准库register_functions(L); // 注册 C++ 函数if (luaL_dofile(L, "script.lua")) { // 执行 Lua 脚本std::cerr << "Failed to load script: " << lua_tostring(L, -1) << std::endl;lua_pop(L, 1); // 从堆栈中移除错误消息}lua_close(L); // 关闭 Lua 状态return 0;
}
2. 批量注册(luaL_Reg)
// cpp
typedef struct luaL_Reg {const char *name; // 函数的名字lua_CFunction func; // 对应的 C 函数
} luaL_Reg;void luaL_newlib (lua_State *L, const luaL_Reg l[]);
/*这个实际上是 luaL_newlibtable 和 luaL_setfuncs两个函数的组合:void luaL_newlibtable(lua_State *L, const luaL_Reg l[]);
其中l为指向 luaL_Reg 结构体数组的指针,该数组定义了库中的函数。
luaL_newlibtable 是 Lua C API 提供的一个函数,用于创建一个新的空表,
这个表的大小预分配为注册表中定义的库函数数量。
这在创建一个新的 Lua 库时特别有用,因为它可以预先分配合适的空间以容纳所有的库函数,避免动态扩展表的开销。void luaL_setfuncs(lua_State *L, const luaL_Reg *l, int nup);
l:指向 luaL_Reg 结构体数组的指针,该数组定义了库中的函数。
nup:传递给每个函数的 upvalue 数量。通常为 0。
luaL_setfuncs用于将 C 函数数组注册到一个 Lua 表中。
*/
示例
// cpp
#include <lua.hpp>
#include <iostream>// C 函数:加法
int add(lua_State* L) {int a = luaL_checkinteger(L, 1);int b = luaL_checkinteger(L, 2);lua_pushinteger(L, a + b);return 1;
}// C 函数:减法
int sub(lua_State* L) {int a = luaL_checkinteger(L, 1);int b = luaL_checkinteger(L, 2);lua_pushinteger(L, a - b);return 1;
}// 创建 Lua 库
extern "C" int luaopen_mylib(lua_State* L) {luaL_Reg mylib[] = {{"add", add},{"sub", sub},{NULL, NULL}};luaL_newlib(L, mylib);return 1;
}int main() {lua_State* L = luaL_newstate();luaL_openlibs(L);luaopen_mylib(L); // 手动打开库(如果需要)if (luaL_dofile(L, "script.lua")) {std::cerr << "Failed to load script: " << lua_tostring(L, -1) << std::endl;lua_pop(L, 1);}lua_close(L);return 0;
}
-- script.lua
local mylib = require("mylib")local result_add = mylib.add(10, 20)
print("Result of add(10, 20):", result_add)local result_sub = mylib.sub(20, 10)
print("Result of sub(20, 10):", result_sub)
相关文章:
Lua与C交互API接口总结
Lua与C交互 1. 常见Lua相关的C API压入元素查询元素获取元素检查元素栈的相关数据操作 2. C调用Lua核心调用函数示例 3. Lua调用C1. C函数注册到Lua(lua_register)示例2. 批量注册(luaL_Reg)示例 1. 常见Lua相关的C API 压入元素…...
DT浏览器很好用
简单的浏览器,又是强大的浏览器,界面简洁大方,操作起来非常流畅😎,几乎不会有卡顿的情况。 搜索功能也十分强大👍,能够快速精准地找到想要的信息。 而且还有出色的兼容性,各种网页都…...
RabbitMQ实践——在管理后台测试消息收发功能
在《RabbitMQ实践——在Ubuntu上安装并启用管理后台》中,我们搭建完RabbitMQ服务以及管理后台。本文我们将管理后台,进行一次简单的消息收发实验。 赋予admin账户权限 登录到管理后台,进入到用户admin的管理页面 点击“set permission”&a…...
vscode卡顿问题处理(vue-official插件)
vue官方扩展由volar升级为vue-official,部分人的ide会变得非常卡顿,这是由于vscode本身一些问题导致,如下图作者解释: 解决方式: 通过禁用Hybrid模式,不使用tsserver来接管语言支持,卡顿会缓解…...
使用Kube-Bench对Kubernetes进行安全检测
使用Kube-Bench对Kubernetes进行安全检测 1. 工具介绍 Kube-Bench是一个开源的Go语言工具,用于自动化检查Kubernetes集群是否符合CIS Kubernetes基准。这些基准包括一系列关于Kubernetes配置和部署安全性的建议和最佳实践。 Kube-Bench执行了一系列针对Kubernete…...
STM32开发过程中碰到的问题总结 - 1
文章目录 前言1. 怎么生成keil下可以使用的文件和gcc下编译使用的makefile2. STM32的时钟树3.怎么查看keil5下的编译工具链用的是哪个4. Arm编译工具链和GCC编译工具链有什么区别吗?5. 怎么查看Linux虚拟机是x86的还是aarch646. 怎么下载gcc-arm的编译工具链7.怎么修…...
hiberfil.sys文件在Windows系统作用
hiberfil.sys文件在Windows系统中起着关键的作用,主要涉及到计算机的休眠功能。以下是关于hiberfil.sys的详细解释: 定义与功能: hiberfil.sys是Windows休眠功能(Windows Hibernation)将内存数据与会话保存至硬盘所需…...
智能制造前沿:ARMxy工控机在机器人控制中
机器人控制系统正逐步成为现代制造业的核心引擎。在这个过程中,ARMxy工业计算机以其独特的优势,成为了驱动这一变革的关键力量。本文将以自动化装配线机器人为例,探讨ARMxy如何通过其低功耗、高性能特性,以及高度灵活性的设计&…...
【CS.AI】AI引领编程新时代:深度探索GitHub Copilot
文章目录 引言0. TOP TAKEAWAYS 重要要点1. Copilot的基本功能2. 技术原理3. 优势与局限优势局限 4. 使用体验4.1 初次使用4.2 在 JetBrains 全家桶中使用 GitHub Copilot1. 安装插件2. 配置插件3. 使用 GitHub Copilot 4.3 日常开发4.4 体验与反馈 5. 对开发者生态系统的影响5…...
Java:爬虫htmlunit抓取a标签
如果对htmlunit还不了解的话可以参考Java:爬虫htmlunit-CSDN博客 了解了htmlunit之后,我们再来学习如何在页面中抓取我们想要的数据,我们在学习初期可以找一些结构比较清晰的网站来做测试爬取,首先我们随意找个网站如下ÿ…...
电池包断路单元DBU的预充电电阻应用案例
当电池组接触器闭合到电机和逆变器上时,逆变器电容器中会有电流涌入。这种非常高的电流至少可能会使接触器老化,并可能永久损坏接触器。 因此,当我们关闭电池组上的接触器时,我们分三个步骤执行此操作: 1.关闭主负极…...
车载网络安全指南 系统层面开发阶段(六)
返回总目录->返回总目录<- 目录 前言 一、统层面产品开发启动 二、系统层面漏洞分析 三、网络安全策略具体化 四、确定网络安全技术需求 五、系统设计 六、系统集成与测试 七、网络安全验证 八、系统层面网络安全评估 九、系统层面产品开发阶段检查 十、产品发…...
Julia 文件读写
Julia 文件读写 Julia 是一种高性能的动态编程语言,特别适合于数值计算和科学计算。在数据处理和科学研究中,文件读写是一项基本且重要的技能。Julia 提供了一套丰富的函数和库来处理文件读写操作,使得文件操作变得简单而高效。 基本文件操作 打开和关闭文件 在 Julia 中…...
为何总是会失败
总是失败可能涉及多种因素,但这里有一些常见原因和对应的建议,或许可以帮助你找到问题所在并加以改进。 1. 目标不明确 原因 目标不清晰或设定过高会导致失望和挫折感。如果目标不明确,行动就会缺乏方向,导致效率低下和失败。 …...
【PB案例学习笔记】-21小大写金额转换
写在前面 这是PB案例学习笔记系列文章的第21篇,该系列文章适合具有一定PB基础的读者。 通过一个个由浅入深的编程实战案例学习,提高编程技巧,以保证小伙伴们能应付公司的各种开发需求。 文章中设计到的源码,小凡都上传到了gite…...
12.实战私有数据微调ChatGLM3
实战私有数据微调ChatGLM3 实战私有数据微调ChatGLM3实战构造私有的微调数据集基于 ChatGPT 设计生成训练数据的 Prompt使用 LangChain GPT-3.5-Turbo 生成训练数据样例训练数据解析、数据增强和持久化存储自动化批量生成训练数据集流水线提示工程(Prompt Engineer…...
PHP地方门户分类信息网站源码讯客分类信息系统源码(含手机版)
源码介绍 1.上传程序到网站根目录,访问http://域名/install/index.php 进行安装,不要直接打开网址,先直接安装; 2.安装完成后 后台恢复数据即可 默认帐号密码都是admin http://域名/admin/ 3.不要删除任何文件,因为删除文件或者修改代码可能造成错误 运…...
设计模式 —— 观察者模式
设计模式 —— 观察者模式 什么是观察者模式观察者模式定义观察者模式的角色观察者模式的使用场景观察者模式的实现 被观察者(Subject)观察者(Observer)通知(notify)更新显示(update)…...
光纤跳线(又称光纤连接器)的种类
光纤跳线(又称光纤连接器),也就是接入光模块的光纤接头,也有好多种,且相互之间不可以互用。SFP模块接LC光纤连接器,而GBIC接的是SC光纤连接器。下面对网络工程中几种常用的光纤连接器进行详细的说明&#x…...
探索Ubuntu:从入门到精通
目录 一、什么是Ubuntu? 1.1 Ubuntu的定义和背景 1.2 Ubuntu的特点 二、安装Ubuntu 2.1 下载Ubuntu安装镜像 2.2 制作启动盘 2.3 安装Ubuntu 三、初步设置和基本操作 3.1 系统更新 3.2 安装必要软件 3.3 设置和管理用户账户 四、文件和目录管理 4.1 文件管理器 …...
浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)
✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义(Task Definition&…...
YSYX学习记录(八)
C语言,练习0: 先创建一个文件夹,我用的是物理机: 安装build-essential 练习1: 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件,随机修改或删除一部分,之后…...
【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)
升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点,但无自动故障转移能力,Master宕机后需人工切换,期间消息可能无法读取。Slave仅存储数据,无法主动升级为Master响应请求ÿ…...
ArcGIS Pro制作水平横向图例+多级标注
今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作:ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等(ArcGIS出图图例8大技巧),那这次我们看看ArcGIS Pro如何更加快捷的操作。…...
laravel8+vue3.0+element-plus搭建方法
创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...
Angular微前端架构:Module Federation + ngx-build-plus (Webpack)
以下是一个完整的 Angular 微前端示例,其中使用的是 Module Federation 和 npx-build-plus 实现了主应用(Shell)与子应用(Remote)的集成。 🛠️ 项目结构 angular-mf/ ├── shell-app/ # 主应用&…...
七、数据库的完整性
七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...
tomcat入门
1 tomcat 是什么 apache开发的web服务器可以为java web程序提供运行环境tomcat是一款高效,稳定,易于使用的web服务器tomcathttp服务器Servlet服务器 2 tomcat 目录介绍 -bin #存放tomcat的脚本 -conf #存放tomcat的配置文件 ---catalina.policy #to…...
【Veristand】Veristand环境安装教程-Linux RT / Windows
首先声明,此教程是针对Simulink编译模型并导入Veristand中编写的,同时需要注意的是老用户编译可能用的是Veristand Model Framework,那个是历史版本,且NI不会再维护,新版本编译支持为VeriStand Model Generation Suppo…...
xmind转换为markdown
文章目录 解锁思维导图新姿势:将XMind转为结构化Markdown 一、认识Xmind结构二、核心转换流程详解1.解压XMind文件(ZIP处理)2.解析JSON数据结构3:递归转换树形结构4:Markdown层级生成逻辑 三、完整代码 解锁思维导图新…...
