在Lua解释器中注册自定义函数

news2024/10/7 6:50:54

本文目录

  • 1、引言
  • 2、函数注册
    • 2.1注册原理
    • 2.2 注册函数
  • 3、实操
    • 3.1 编写注册函数
    • 3.2编写测试代码
  • 4、结论


文章对应视频教程:

暂无,可以关注我的B站账号等待更新。


点击图片或链接访问我的B站主页~~~


1、引言

在之前的博客中,已经介绍了如何在ANSI C环境中运行lua解释器了。
但只是开始,我们移植lua解释器更多的是为了能让lua解释器能控制我们的硬件或者逻辑,这样lua与底层C语言的交互就尤其重要了。


2、函数注册

2.1注册原理

使用函数#define lua_register(L,n,f) (lua_pushcfunction(L, (f)), lua_setglobal(L, (n)))
将c语言的函数注册到lua环境中,并申明一个别名。
例如:

    lua_register(L,"create_rectangle",create_rectangle);
    lua_register(L,"set_xy",set_xy);
    lua_register(L,"get_area",get_area);
    lua_register(L,"get_perimeter",get_perimeter);

第二个参数是lua解释器中的别名,第三个是C语言中的函数指针。

2.2 注册函数

C语言要注册一个函数到lua环境中,需要采用一定的形式:

static int create_rectangle(lua_State *L)
{
    if(obj_num >= 9 )
    {
        lua_pushinteger(L,-1);
        return 1;
    }
    lua_pushinteger(L,obj_num);
    obj_num++;
    return 1;
}

首先函数必须是int xxxxx(lua_State *L)
如果这个注册的lua函数存在参数输入,在Lua中调用C函数时,所有参数都通过栈传递。C函数通过lua_gettop(lua_State *L)来获取参数的个数。例如:

int argc = lua_gettop(L);

这个函数返回当前栈的大小,也就是传递给函数的参数个数。

在Lua中,参数可以是多种类型,如数字、字符串、表等。在C函数中需要检查参数的类型以确保正确处理。

读取参数API


lua_gettop(L):返回栈顶的索引(即参数个数)。
lua_isnumber(L, index):检查栈中指定位置上的值是否为数字类型。
lua_isinteger(L, index):检查栈中指定位置上的值是否为整数类型。
lua_isboolean(L, index):检查栈中指定位置上的值是否为布尔类型。
lua_isstring(L, index):检查栈中指定位置上的值是否为字符串类型。
lua_istable(L, index):检查栈中指定位置上的值是否为表类型。
lua_isnil(L, index):检查栈中指定位置上的值是否为nil。
lua_islightuserdata(L, index):检查栈中指定位置上的值是否为轻量级用户数据。
lua_tonumber(L, index):将栈中指定位置上的值转换为数字类型。
lua_tointeger(L, index):将栈中指定位置上的值转换为整数类型。
lua_toboolean(L, index):将栈中指定位置上的值转换为布尔类型。
lua_tostring(L, index):将栈中指定位置上的值转换为字符串类型。
lua_touserdata(L, index):将栈中指定位置上的值转换为用户数据类型。
lua_rawlen(L, index):返回栈中指定位置上的值的长度(对于字符串或表)。

例如,从Lua获取两个数字参数:

if (!lua_isnumber(L, 1) || !lua_isnumber(L, 2)) {
    lua_pushstring(L, "Expected two numbers");
    lua_error(L);
    return 0;
}
double a = lua_tonumber(L, 1);
double b = lua_tonumber(L, 2);

返回值与return的关系
在C函数中,将结果返回给Lua时,需要将结果压入栈中,并且返回结果的数量。返回值数量由C函数的返回值指定,Lua虚拟机会根据这个数量从栈顶取出相应的值。

例如,返回一个结果(即函数求和的结果):

double result = a + b;
lua_pushnumber(L, result);
return 1; // 返回值的数量是1

如果需要返回多个值,则依次将这些值压入栈中,并返回相应的数量。例如:

int add_and_subtract(lua_State *L) {
    if (lua_gettop(L) != 2) {
        lua_pushstring(L, "Expected exactly two arguments");
        lua_error(L);
        return 0;
    }
    double a = lua_tonumber(L, 1);
    double b = lua_tonumber(L, 2);

    double sum = a + b;
    double diff = a - b;

    lua_pushnumber(L, sum);   // 第一个返回值
    lua_pushnumber(L, diff);  // 第二个返回值

    return 2; // 返回值的数量是2
}

返回参数API

lua_pushnumber(L, n):将一个数字压入栈中。
lua_pushinteger(L, n):将一个整数压入栈中。
lua_pushboolean(L, b):将一个布尔值压入栈中。
lua_pushstring(L, s):将一个字符串压入栈中。
lua_pushlstring(L, s, len):将一个指定长度的字符串压入栈中。
lua_pushnil(L):将nil压入栈中。
lua_pushlightuserdata(L, p):将一个轻量级用户数据压入栈中。
lua_pushcclosure(L, fn, n):将一个C闭包压入栈中。
lua_pushvalue(L, index):将指定索引处的值压入栈中。
lua_newtable(L):创建一个新的空表并压入栈中。
lua_pushthread(L):将当前线程压入栈中。

3、实操

3.1 编写注册函数

创建一个lua_func.c的文件,内容如下:

#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"

typedef struct {
	int x;
	int y;
} rectangle;

#define MAX_OBJ_NUM  10

static rectangle obj[MAX_OBJ_NUM] ;
static int obj_num = 0;

static int create_rectangle(lua_State *L)
{
    if(obj_num >= 9 )
    {
        lua_pushinteger(L,-1);
        return 1;
    }
    lua_pushinteger(L,obj_num);
    obj_num++;
    return 1;
}
static int set_xy(lua_State *L)
{

	int index = 	lua_tointeger(L, 1);
	int x = lua_tointeger(L, 2);
	int y = lua_tointeger(L, 3);
	
    obj[index].x = x;
    obj[index].y = y;
	return 0;
}

static int get_area(lua_State *L)
{

	int index = 	lua_tointeger(L, 1);
	
    int obj_area = obj[index].x * obj[index].y ;
    lua_pushinteger(L,obj_area);
	return 1;
}


static int get_perimeter(lua_State *L)
{

	int index = 	lua_tointeger(L, 1);
	
    int obj_peri = (obj[index].x + obj[index].y)*2 ;
    lua_pushinteger(L,obj_peri);
	return 1;
}



void lua_func_register(lua_State *L)
{
    lua_register(L,"create_rectangle",create_rectangle);
    lua_register(L,"set_xy",set_xy);
    lua_register(L,"get_area",get_area);
    lua_register(L,"get_perimeter",get_perimeter);
}


这个文件创建了4个函数,用于注册到lua环境中。
main.c中调用 lua_func_register(L);函数。

3.2编写测试代码

创建一个func.lua的新测试脚本,内容如下:

-- func test
obj1 = create_rectangle()
print("rectangle index is:",obj1)
obj2 = create_rectangle()
print("rectangle index is:",obj2)

set_xy(obj1,5,10);
set_xy(obj2,6,8);

print("rectangle",obj1,"area is:",get_area(obj1))
print("rectangle",obj2,"area is:",get_area(obj2))

print("rectangle",obj1,"perimeter is:",get_perimeter(obj1))
print("rectangle",obj2,"perimeter is:",get_perimeter(obj2))

更改main函数中打开的lua文件名字

   file = fopen("func.lua", "rb"); // 使用"rb"模式以二进制方式读取文件

4、结论

在工程路径下输入python .\ck_script.py a配置、构建、编译项目
在这里插入图片描述
执行程序,结果如下,说明我们注册自定义的lua函数成功。
在这里插入图片描述


时间流逝、年龄增长,是自己的磨炼、对知识技术的应用,还有那不变的一颗对嵌入式热爱的心!

到这里就结束了!希望大家给我的文章和B站视频
点赞o( ̄▽ ̄)d、关注(o)/~、评论(▽)!

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

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

相关文章

JEPaaS 低代码平台 j_spring_security_check SQL注入漏洞复现

0x01 产品简介 JEPaaS是一款优秀的软件平台产品,可视化开发环境,低代码拖拽式配置开发,操作极其简单,可以帮助解决Java项目80%的重复工作,让开发更多关注业务逻辑,大大提高开发效率,能帮助公司大幅节省人力成本和时间成本,同时又不失灵活性。适用于搭建 OA、ERP、CRM、…

基于WPF技术的换热站智能监控系统07--实现左侧数据报表

1、区域划分 2、UI布局 LiveCharts是一个比较漂亮的WPF图表控件,在数据变化时还会有动画切换的效果,并且样式也可以控制。 Values:数据值 Fill:填充颜色 StrokeThickness:粗细 LabelPosition:标签位置 3、运行效果 走过路过不…

便携式EL检测仪:高效便捷的太阳能组件光伏EL检测设备

TH-EL2随着全球对可再生能源的日益重视,太阳能作为清洁、可再生的能源形式,受到了广泛的关注和应用。太阳能光伏组件作为太阳能发电系统的核心部件,其质量直接关系到整个系统的发电效率和寿命。因此,对太阳能光伏组件进行高效、准…

网格细分技术在AI绘画中的革新应用

导语: 随着人工智能技术的不断突破,艺术创作也迈入了一个新的时代。AI绘画不仅为艺术家提供了新的工具和灵感源泉,还极大地扩展了艺术的边界。在这背后,网格细分技术扮演着至关重要的角色,它通过将画面划分为数以万计的…

FlowUs本地部署:数据自主权与定制化服务的完美融合|FlowUs息流企业级解决方案本地私有化部署|FlowUs本地部署保证客户数据安全

在当今数字化时代,企业对数据的控制和安全性要求越来越高,同时,用户对软件的使用习惯也趋向多样化。针对这些需求,FlowUs作为一款多功能的协作平台,提供了灵活的解决方案。 FlowUs本地部署 对于有本地化需求的客户&a…

人工智能代理:关键概念及如何克服LLM限制

人工智能代理是一种自主软件实体,通常用于增强大型语言模型。以下是开发人员需要了解的内容。 随着大型语言模型 (LLM) 变得更加强大,一种被称为“代理”的新型软件应运而生,以增强和提升 LLM 的能力。本文介绍了代理的关键概念以及它们如何…

【Mac】精通或死亡Spellz Mastery or Death(角色扮演游戏))游戏介绍

前言 今天给大家介绍一款游戏,《精通或死亡Spellz Mastery or Death for mac》(角色扮演游戏) 。 游戏介绍 《精通或死亡:Spellz Mastery or Death》是一款以魔法为核心的策略角色扮演游戏(RPG),玩家在游戏中需要掌…

干货分享:宏集物联网HMI通过S7 MPI协议采集西门子400PLC数据

前言 为了实现和西门子PLC的数据交互,宏集物联网HMI集成了S7 PPI、S7 MPI、S7 Optimized、S7 ETH等多个驱动来适配西门子200、300、400、1200、1500、LOGO等系列PLC。 本文主要介绍宏集HMI通过S7 MPI协议采集西门子400PLC数据的操作步骤,其他协议的操作…

​揭秘Grok大模型:未来AI的无限可能

🚀 大家好,今天我们要带大家走进一个充满未来科技感的世界,探秘一款备受瞩目的大模型——Grok! 一、Grok背后的神秘力量 Grok,这个名字可能对于大多数人来说还是陌生的,但它背后的公司——xAI&#xff0c…

3D线扫相机中的深度数据与激光反射强度数据获取及其应用

1. 引言 3D线扫相机(3D line scan camera)是一种高精度的三维测量设备,广泛应用于工业自动化、质量控制和精密测量等领域。与传统二维成像相机不同,3D线扫相机能够同时获取物体的深度信息和反射强度信息,从而为高精度…

【小白学Python】自定义图片的生成(二)

Python学习 【小白学Python】自定义图片的生成(一) 目录 1. 文件内容2.生成图片规则3. 修改代码2.1 尝试一行汉字展示3.1 读取txt文件3.2 解决文字过长问题3.3 删减指定文字 4. 总结 1. 文件内容 正如上篇文章所说,我需要读取txt文件的文字内…

MYSQL基础_12_MySQL数据类型精讲

第12章_MySQL数据类型精讲 1. MySQL中的数据类型 类型类型举例整数类型TINYINT、SMALLINT、MEDIUMINT、INT(或INTEGER)、BIGINT浮点类型FLOAT、DOUBLE定点数类型DECIMAL位类型BIT日期时间类型YEAR、TIME、DATE、DATETIME、TIMESTAMP文本字符串类型CHAR、VARCHAR、TINYTEXT、TE…

Milvus Cloud 问答机器人 上线!构建企业级的 Chatbot

01. 背景 早些时候我们在社区微信群发出了一份关于Milvus Cloud 自动问答机器人的调研问卷。 调研受到了社区同学的积极响应,很快我们就收到了很多热心用户的回复。 基于这些回复,我们整理出了 Milvus Cloud Chatbot 的形态: 以功能使用和文档查询为核心 提供聊天和搜索双形…

小程序在IOS系统的兼容性

1、使用textarea标签,小程序在苹果手机中展示有bug 上面就是因为使用了textarea标签导致,换成text或者view就可以展示了 2、scroll-view横向滚动出现bug 解决办法:直接手写view加样式overflow:scroll用系统自带的滚动条

CPN Tools实现hello world小案例

新建一个net,创建两个输入P1,P2,一个输出P3,一个转换T1,并对输入输出place使用字符串颜色集。(这里是左键单击P,然后tab键输入String即可)。 为地点指定颜色集需要: 1) 通过左键单击…

以 ZGC 为例,谈一谈 JVM 是如何实现 Reference 语义的

本文基于 OpenJDK17 进行讨论 1. Reference 相关概念及其应用场景总览 Reference(引用)是 JVM 中非常核心且重要的一个概念,垃圾回收器判断一个对象存活与否都是围绕着这个 Reference 来的,JVM 将 Reference 又细分为几种具体的引…

天锐绿盾 | 无感知加密软件、透明加密系统、数据防泄漏软件

摘要:文件加密软件,包含禁止非授权的文件泄密和抄袭复制解决方案即使被复制泄密都是自动加密无法阅读,透明加密,反复制软件,内网监控,文件加密,网络安全方案,透明文件加密,加密文件,图纸加密,知识产权保护,加密数据; 通过绿盾信息安全管理软件,系统在不改…

Talk|CVPR‘24 Oral:超越3D - Point Transformer V3中的多模态特征提取新构想

本期为TechBeat人工智能社区第599期线上Talk。 北京时间6月12日(周三)20:00,香港大学博士生—吴虓杨的Talk已经准时在TechBeat人工智能社区开播! 他与大家分享的主题是: “超越3D - Point Transformer V3中的多模态特征提取新构想”,他通过P…

Scapy使用报错Interface is invalid (no pcap match found) 解决办法

在win10环境下,想用scapy写一个通过arp协议扫描局域网的程序,主要是想看看有多少个设备在线。多次尝试未果,显示的错误信息有时为Interface is invalid,有时Interface is invalid (no pcap match found) ,为了让程序能…

Flask快速入门

Flask快速入门(路由、CBV、请求和响应、session) 目录 Flask快速入门(路由、CBV、请求和响应、session)安装创建页面Debug模式快速使用Werkzeug介绍watchdog介绍快速体验 路由系统源码分析手动配置路由动态路由-转换器 Flask的CBV…