本文目录
文章对应视频教程:
暂无,可以关注我的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)/~、评论(▽)!