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

本文目录


文章对应视频教程:

暂无,可以关注我的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环境中,并申明一个别名。

例如:

c 复制代码
    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环境中,需要采用一定的形式:

c 复制代码
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)来获取参数的个数。例如:

c 复制代码
int argc = lua_gettop(L);

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

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

读取参数API

c 复制代码
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获取两个数字参数:

c 复制代码
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虚拟机会根据这个数量从栈顶取出相应的值。

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

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

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

c 复制代码
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

c 复制代码
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的文件,内容如下:

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的新测试脚本,内容如下:

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文件名字

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

4、结论

在工程路径下输入python .\ck_script.py a配置、构建、编译项目

执行程序,结果如下,说明我们注册自定义的lua函数成功。


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

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

相关推荐
红黑色的圣西罗7 分钟前
Lua 怎么解决闭包内存泄漏问题
开发语言·lua
小林熬夜学编程9 分钟前
【Linux系统编程】第四十一弹---线程深度解析:从地址空间到多线程实践
linux·c语言·开发语言·c++·算法
墨墨祺21 分钟前
嵌入式之C语言(基础篇)
c语言·开发语言
躺不平的理查德33 分钟前
数据结构-链表【chapter1】【c语言版】
c语言·开发语言·数据结构·链表·visual studio
幼儿园园霸柒柒2 小时前
第七章: 7.3求一个3*3的整型矩阵对角线元素之和
c语言·c++·算法·矩阵·c#·1024程序员节
好想有猫猫2 小时前
【51单片机】串口通信原理 + 使用
c语言·单片机·嵌入式硬件·51单片机·1024程序员节
摆烂小白敲代码3 小时前
背包九讲——背包问题求方案数
c语言·c++·算法·背包问题·背包问题求方案数
stm 学习ing3 小时前
C语言 循环高级
c语言·开发语言·单片机·嵌入式硬件·算法·嵌入式实时数据库
w微信150135078124 小时前
小华一级 代理商 HC32F005C6PA-TSSOP20 HC32F005系列
c语言·arm开发·单片机·嵌入式硬件
1 9 J5 小时前
数据结构 C/C++(实验三:队列)
c语言·数据结构·c++·算法