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)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/26788.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

大模型微调出错的解决方案(持续更新)

大家好,我是herosunly。985院校硕士毕业,现担任算法研究员一职,热衷于机器学习算法研究与应用。曾获得阿里云天池比赛第一名,CCF比赛第二名,科大讯飞比赛第三名。拥有多项发明专利。对机器学习和深度学习拥有自己独到的见解。曾经辅导过若干个非计算机专业的学生进入到算法…

等保测评练习题11

等级保护初级测评师试题11 姓名&#xff1a; 成绩&#xff1a; 判断题&#xff08;10110分&#xff09; 1.国家支持网络运营者之间在网络安全信息收集、分析、通报和应急处置等方面进行合作。&#xff08;T&#xff09; 安全法第二…

【文献阅读】基于高阶矩的波形分类方法

文章目录 基本信息SND及其统计特征分类 基本信息 【2017】rse Moritz, Bruggisser, Andreas, et al. Retrieval of higher order statistical moments from full-waveform LiDAR data for tree species classification[J]. Remote Sensing of Environment, 2017,196: 28-41. …

鲁教版八年级数学下册-笔记

文章目录 第六章 特殊平行四边形1 菱形的性质与判定2 矩形的性质与判定3 正方形的性质与判定 第七章 二次根式1 二次根式2 二次根式的性质3 二次根式的加减二次根式的乘除 第八章 一元二次方程1 一元二次方程2 用配方法解一元二次方程3 用公式法解一元二次方程4 用因式分解法解…

css系列:音频播放效果-波纹律动

介绍 语音播放的律动效果&#xff0c;通俗来说就是一个带动画的特殊样式的进度条&#xff0c;播放的部分带有上下律动的动画&#xff0c;未播放的部分是普通的灰色竖状条。 实现中夹带了less变量、继承和循环遍历&#xff0c;可以顺带学习一下。 结果展示 大致效果如图所示…

防火墙安全管理

大多数企业通过互联网传输关键数据&#xff0c;因此部署适当的网络安全措施是必要的&#xff0c;拥有足够的网络安全措施可以为网络基础设施提供大量的保护&#xff0c;防止黑客、恶意用户、病毒攻击和数据盗窃。 网络安全结合了多层保护来限制恶意用户&#xff0c;并仅允许授…

使用QT制作QQ登录界面

mywidget.cpp #include "mywidget.h"Mywidget::Mywidget(QWidget *parent): QWidget(parent) {/********制作一个QQ登录界面*********************/this->resize(535,415);//设置登录窗口大小this->setFixedSize(535,415);//固定窗口大小this->setWindowTi…

Spring Boot 的启动原理、Spring Boot 自动配置原理

Spring Boot启动原理包含自动装配原理。 Spring Boot 的启动原理&#xff1a; 1. 入口类与 SpringApplication 初始化&#xff1a; 应用程序通常从一个带有 SpringBootApplication 注解的主类开始&#xff0c;这个注解是一个组合注解&#xff0c;包含了 SpringBootConfigurat…

【学习笔记8】阅读StyleID论文源码

论文【链接】 源码【链接】 一、DDIM eta ddim_step表示执行几轮去噪迭代&#xff0c;eta表示DDPM和DDIM的插值系数。当eta0时&#xff0c;为DDPM&#xff1b;当eta≠0时&#xff0c;为DDIM。 参考 DDIM 简明讲解与 PyTorch 实现&#xff1a;加速扩散模型采样的通用方法 【s…

2024.06.13

这两天一直在准备面试和进行面试啊&#xff0c; 从昨天面七牛云&#xff0c;到今天面百度和蔚来&#xff0c;学到了很多不只是知识上的内容&#xff0c;详情可看&#xff1a;我的牛客

【ARMv8/ARMv9 硬件加速系列 3 -- SVE 硬件加速向量运算 1】

文章目录 SVE 使用介绍SVE 特点SVE2 特点 SVE 寄存器扩展的向量寄存器可扩展的谓词寄存器.d 与 .b 后缀的区别举例介绍使用 .d 后缀进行64位元素操作使用 .b 后缀进行8位元素操作 ptrue 指令小结 FFR 寄存器 SVE 使用介绍 前面文章:【ARMv8/ARMv9 硬件加速系列 1 – SVE | NEO…

git下载项目登录账号或密码填写错误不弹出登录框

错误描述 登录账号或密码填写错误不弹出登录框 二、解决办法 控制面板\用户帐户\凭据管理器 找到对应的登录地址进行更新或者删除 再次拉取或者更新就会提示输入登录信息

影响数字本振信噪比的因素

2048 点 -66 4096 点-72 8192 点-77 16384 点-84

FineBI开发中的一些数据处理方法

在这里记录在FineBI开发中的遇到的一些数据处理方法。 1、获取一星期中的首日日期 假设电商数据分析场景中有张订单表&#xff0c;其中有一列为订单日期(order_create_dt)&#xff0c;如果需要统计订单金额周同比&#xff0c;一般我们都需要构建一张日期维度表&#xff08;如…

SAP PP学习笔记21 - 计划策略的Customize:策略组 > 策略 > 需求类型 > 需求类(消费区分,计划区分)

上面几章讲了MTS&#xff0c;MTO&#xff0c;ATO的计划策略。 本章来讲一下它的后台 Customize。 1&#xff0c;Customizeing&#xff1a;Planned Indep.Reqmts Management 这是配置计划策略的整个过程&#xff1a; - Requirements Type / Class 需求类型 / 需求类 - Plann…

VUE之重定向redirect

VUE之路由和重定向redirect 这个小知识点是在学习做项目的时候遇到的一个问题&#xff0c;借鉴了一个他人的项目&#xff0c;是一个酒店管理系统&#xff0c;拿到源码之后导到我的vscode里。 参考链接 导的过程比较顺利&#xff0c;正常安装&#xff0c;加依赖&#xff0c;没有…

SIM卡 移动、联通、电信对比

中国移动、联通、电信优势劣势分析 移动和联通采用GSM终端&#xff0c;电信采用CDMA终端(码分多址)&#xff0c;上网速度快&#xff0c;保密性好联通也有CDMA关于GSM、CDMA、TDMA、 TD-SCDMA、WCDMA之间的各种纠结 中国联通&#xff1a;网络安全的“攻”与“防” 联通保密性…

java操作数据库语法

1 新建数据库 1.1 新建数据库 1 启动mysql数据库 2 新建数据库 1.2 mysql数据库语法 1 选择数据库 use java_demo1 2 移除数据库 drop database java_web1 3 创建表 CREATE TABLE user (id int(11) PRIMARY KEY AUTO_INCREMENT,name varchar(255) NOT NULL,age int(11)…

【python】通行网格地图四叉树化 (leeccode 427)

【python】通行网格地图四叉树化 受到Leecode 427题的启发&#xff0c;427. 建立四叉树 想将由0和1组成的网格地图绘制为四叉树地图&#xff0c;0表示可通行网格&#xff0c;1表示不可通行网格。 import matplotlib.pyplot as plt import matplotlib.patches as patches …

【数学建模】MATLAB入门教程:插值与拟合(下)

前言 插值与拟合在数据处理和科学计算中扮演着非常重要的角色&#xff0c;它们用于估算未知数据点的值&#xff0c;帮助我们理解和预测数据趋势 一、一维插值 1、一维插值定义 已知n1个节点(,)(j0,1,...,n,其中互不相同&#xff0c;不妨设a<<...<b),求任一插值点(…