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

本文目录

  • 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)/~、评论(▽)!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

JAVA小知识17:数组,从0基础到掌握

数组,无论在哪种编程语言当中都是最基础,最广泛使用的一种线性表数据结构,这篇文章将从多个角度来从浅入深的讲述数组。 本文讲述了数组的概念,定义,初始化方法以及如何遍历数组,如何赋值,关于数…

4. Revit API UI 之 Ribbon(界面)

4. Revit API UI 之 Ribbon(界面) 第二篇中,我们提到了IExternalApplication,该接口需要实现两个方法:Revit启动时调用的OnStartup 方法,和Revit关闭时调研的OnShutdown 方法。文中还给了个例子&#xff0…

剧透!「飞凌嵌入式技术创新日」3大亮点抢先看

6月25日,飞凌嵌入式技术创新日(北京站)即将开幕,一场嵌入式前沿科技的高端局就在眼前。 飞凌嵌入式作为国内较早专业从事嵌入式技术的企业,凭借18年的行业深耕和丰富的技术积累,已在业界赢得了广泛的影响力…

LabVIEW电源适应能力检测系统

随着工业自动化程度的提高,电源质量直接影响设备的稳定运行。利用LabVIEW开发一个单相电源适应能力检测系统,该系统通过智能化和自动化测试,提高了测试效率,减少了人为错误,保证了电源质量的可靠性。 项目背景 在现代…

大厂面试必备:如何轻松实现分布式Session管理?

我是小米,一个喜欢分享技术的29岁程序员。如果你喜欢我的文章,欢迎关注我的微信公众号“软件求生”,获取更多技术干货!​​​​​​​ 大家好,我是小米,一个29岁的技术爱好者,喜欢分享各种技术干货。今天我们来聊一聊阿里巴巴面试中的一个经典问题:如何实现分布式Sess…

HCIA12 NAT网络地址转换实验

NAT(Network Address Translation)是将 IP 报头中的 IP 地址转换为另一个 IP 地址的过程。主要俩好处: • 有效避免来自外网的攻击,可以很大程度上提高网络安全性。 • 控制内网主机访问外网,同时也可以控制外网…

你的医书是假的!批评《DDD诊所——聚合过大综合症》(合集)

DDD领域驱动设计批评文集 做强化自测题获得“软件方法建模师”称号 《软件方法》各章合集 (《你的医书是假的!》原文写于2023年8月,以系列文章方式发表,现合并成一篇文章) 一、说在前面 这两天在“ Thoughtworks洞见…

Mac vscode could not import github.com/gin-gonic/gin

问题背景: 第一次导入一个go的项目就报红 问题分析: 其实就是之前没有下载和导入gin这个web框架包 gin是一个golang的微框架,封装比较优雅,API友好,源码注释比较明确。 问题解决: 依次输入以下命令。通…

【STM32】输入捕获应用-测量脉宽或者频率(方法1)

图1 脉宽/频率测量示意图 1 测量频率 当捕获通道TIx 上出现上升沿时,发生第一次捕获,计数器CNT 的值会被锁存到捕获寄存器CCR中,而且还会进入捕获中断,在中断服务程序中记录一次捕获(可以用一个标志变量来记录&#…

阿里最强开源大模型本地部署、API调用和WebUI对话机器人

阿里巴巴通义千问团队发布了Qwen2系列开源模型,该系列模型包括5个尺寸的预训练和指令微调模型:Qwen2-0.5B、Qwen2-1.5B、Qwen2-7B、Qwen2-57B-A14B以及Qwen2-72B。对比当前最优的开源模型,Qwen2-72B在包括自然语言理解、知识、代码、数学及多…

新加坡裸机云多IP服务器为何适合跨境外贸业务

新加坡裸机云多IP服务器在跨境外贸业务中展现出了卓越的适配性,其独特优势为外贸企业提供了强大的支持。以下将详细阐述为何新加坡裸机云多IP服务器是跨境外贸业务的理想选择。 首先,新加坡裸机云多IP服务器在性能上表现出色。由于去除了虚拟化层的开销&…

聚观早报 | 粉笔将推AI智能老师;比亚迪宋L DM-i车型官宣

聚观早报每日整理最值得关注的行业重点事件,帮助大家及时了解最新行业动态,每日读报,就读聚观365资讯简报。 整理丨Cutie 6月13日消息 粉笔将推AI智能老师 比亚迪宋L DM-i车型官宣 真我GT7 Pro配置全面升级 理想发布最新单周销量榜单 …

如何免费用 Qwen2 辅助你翻译与数据分析?

对于学生用户来说,这可是个好消息。 开源 从前人们有一种刻板印象——大语言模型里好用的,基本上都是闭源模型。而前些日子,Meta推出了Llama3后,你可能已经从中感受到现在开源模型日益增长的威力。当时我也写了几篇文章来介绍这个…

SMT智能车间MES系统的实施方案

SMT行业中MES系统实施的关键特征: SMT包括上下板设备,印刷设备,贴片设备,回流焊炉,AOI。AOI的全称是自动光学检查,它基于光学原理来检测焊接生产中遇到的常见缺陷。测试设备,测试设备等MES解决…

Java多商户商城系统/pc商城/公众号/h5/小程序

>>>系统简述: 基于java vue uniapp 开发的一套 新零售商城系统就是集客户关系管理营销电商系统,能够真正帮助企业基于微信公众号、小程序、移动端等,实现会员管理、数据分析,精准营销的电子商务管理系统。可满足企业新零售、批发…

Vite 为什么这么火?

大家好,我是前端宝哥。 最近,Vite 真是火得不行,几乎每天都能看到关于它的讨论。这个工具到底有多厉害?它为什么这么火? 自从 2020 年 4 月发布以来,Vite 的人气一路飙升。在 GitHub 上已经获得了 64k 的星…

VUE之重定向redirect

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

PHP调用快递地址解析接口助力项目优化

快递地址智能解析是日常开发中一个重要的工具,可以帮助快递公司提高效率,减少错误,进行数据分析。也可以帮助网购用户快速输入收货地址,提升用户体验。 看完以下操作文档,可以让你在开发中以最快时间完成这个功能&…

一维信号的时频分析(Python)

代码较为简单,很容易读懂。 Importing the required libraries import os import numpy as np import pywt import pandas as pd import pickle as pkl from matplotlib import pyplot as plt Parameters or Required Variables DATA_POINTS_PER_FILE 2560 TIM…