Lua调用C的动态库步骤及接口分析

2023-11-18

Lua调用C的动态库

C语言可以完成一些lua不好实现的功能,当程序主体使用lua完成时,便需要掌握该技巧调用C来帮助我们达到目的,通过调用C的动态库简化操作流程。

大致流程如下:

  1. 使用C语言编写方法提供给lua调用
  2. 将C文件打包成动态库
  3. lua导入动态库,直接调用里面的函数

准备工作

确保系统安装lua5.4版本。
首先在目录下创建一个func.c文件和一个call.lua文件,Makefile文件可有可无,主要方便后面编译动态库可以直接使用make。

在这里插入图片描述

使用C语言编写方法

编写需要加入头文件,如下:

#include <lua.h>    	// Lua基础函数库,提供lua_前缀函数
#include <lauxlib.h>    // 辅助库(可以不加),luaL_前缀函数,利用lua.h实现的更高层的抽象

最重要的是定义一个类似main的主函数:luaopen_*函数,在其中注册所要添加方法

  • 在luaopen_func中注册一个函数add,此后lua导入后可以直接通过add调用该函数。
  • 函数返回值必须是int类型,返回值是返回参数的个数。
  • 函数中固定使用参数lua_State,传入参数和返回参数都需要它。
#include <lua.h>
#include <stdio.h>

// 注意,提供给lua调用的方法必须是static int类型的函数
// 返回值表示该函数返回值的个数
// 函数返回值通过lua_push放入堆栈中
static int add(lua_State *L)
{
    printf("C -- add:\n");
    // 解析参数
    int a = lua_tonumber(L, 1);
    int b = lua_tonumber(L, 2);
    printf("a is %d\nb is %d\n", a, b);
    // 返回给lua的值
    lua_pushnumber(L, a + b);
    return 1;
}

int luaopen_func(lua_State *L)
{
    // 注册方法提供调用,前面是调用名称,后面是调用处理函数
    lua_register(L, "add", add);
    return 0;
}

需要注意的地方:

  • 如例子中使用的是luaopen_func,func就是我们之后在lua中导入的库名称,即require “func”,如果这个名字带有下划线如luaopen_func_test,那么lua中导入方法为require “func.test”

将C文件打包成动态库

可以使用命令直接打包,也可以写进makefile中,方便之后同时打包多个动态库

  • 使用一条命令打包单个动态库gcc func.c -o func.so -fPIC -shared,注意func.so命名跟luaopen_后面的命名有关,并不是跟func.c文件名有关。
  • 使用makefile文件
CC := gcc
SRCS := $(wildcard *.c)
TARGETS := $(patsubst %.c, %.so, $(SRCS))
CFLAGS := -fPIC -shared

.PHONY: all clean

all: $(TARGETS)

$(TARGETS):%.so:%.c
    $(CC) $< -o $@ $(CFLAGS)

clean:
    rm -rf $(TARGETS)

打包后如下图
在这里插入图片描述

lua文件中导入动态库并调用其中函数

在同级的call.lua中编写以下代码,直接调用func.so中的函数add

m=require('func')
print("require result:")
print(m)

local a, b = 3, 4
local res = add(a,b)
print("res : " .. res)

运行结果如下:
在这里插入图片描述

以上演示的是简单的单个返回值例子,如果有多个不同类型的返回值该如何去执行呢?

多个返回值方法编写示例

注册一个judge方法,传入name和age和now_year,判断出生年份,返回name+出生年份。
在func.c文件中增加一个judge函数,如下

static int judge(lua_State *L)
{
    // 解析参数
    const char *name = lua_tolstring(L, 1, NULL);
    int age = lua_tonumber(L, 2);
    int now_year = lua_tonumber(L, 3);

    int born_year = now_year - age;

    lua_pushstring(L, name);
    lua_pushnumber(L, born_year);
    // 返回2表示该函数有两个返回值
    return 2;
}

// 同时需要在主函数中注册judge方法提供调用
int luaopen_func(lua_State *L)
{
    // 注册方法提供调用,前面是调用名称,后面是调用处理方法
    lua_register(L, "add", add);
    lua_register(L, "judge", judge);
    return 0;
}

在call.lua中添加响应的调用语句

local name, age, now_year = "glh", 22, 2022
local newname, born_year = judge(name, age, now_year)
print("newname : " .. newname)
print("born_year : " .. born_year)

运行结果如下:
在这里插入图片描述

常用的lua接口

获取函数传入参数
int             (lua_isnumber) (lua_State *L, int idx);    // 判断传入参数是不是数字
int             (lua_isstring) (lua_State *L, int idx);    // 判断传入参数是不是字符串
int             (lua_iscfunction) (lua_State *L, int idx);    // 判断传入参数是不是函数
int             (lua_isuserdata) (lua_State *L, int idx);    // 判断传入参数是不是table?
int             (lua_type) (lua_State *L, int idx);    // 
const char     *(lua_typename) (lua_State *L, int tp);    // 
 
int            (lua_equal) (lua_State *L, int idx1, int idx2);    // 判断传入参数是不是相等
int            (lua_rawequal) (lua_State *L, int idx1, int idx2);    // 
int            (lua_lessthan) (lua_State *L, int idx1, int idx2);    // 


lua_Number      (lua_tonumber) (lua_State *L, int idx);    // 获取传入的number参数
lua_Integer     (lua_tointeger) (lua_State *L, int idx);    // 获取传入的int参数
int             (lua_toboolean) (lua_State *L, int idx);    // 获取传入的bool参数
const char     *(lua_tolstring) (lua_State *L, int idx, size_t *len);    // 获取传入的string参数,注意是传长度地址!
size_t          (lua_objlen) (lua_State *L, int idx);
lua_CFunction   (lua_tocfunction) (lua_State *L, int idx);
void           *(lua_touserdata) (lua_State *L, int idx);
lua_State      *(lua_tothread) (lua_State *L, int idx);
const void     *(lua_topointer) (lua_State *L, int idx);
设置函数返回值
void  (lua_pushnil) (lua_State *L);
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 l);
void  (lua_pushstring) (lua_State *L, const char *s);
const char *(lua_pushvfstring) (lua_State *L, const char *fmt, va_list argp);
const char *(lua_pushfstring) (lua_State *L, const char *fmt, ...);
void  (lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n);
void  (lua_pushboolean) (lua_State *L, int b);
void  (lua_pushlightuserdata) (lua_State *L, void *p);
int   (lua_pushthread) (lua_State *L);

这边只举了一些常用的获取参数和设置返回值的方法,更多详细方法可以参考/usr/include/lua/lua.h头文件。

本文只简单分析了lua.h包含的一些接口并且成功执行调用,更深入的用法可以使用lauxlib.h,此处不多做介绍。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Lua调用C的动态库步骤及接口分析 的相关文章

  • lua检查多个值是否相等

    我喜欢用 Roblox 制作游戏 并用 lua 编写代码 在编写游戏时 我发现自己经常问一个值是否等于另一个值 这可能会产生很长的代码行 并且可能非常重复 例如 如果 x ClassName 衬衫 或x ClassName 附件 或x Cl
  • 为什么这个 Lua 优化 hack 会提高性能?

    我正在寻找一个描述提高 Lua 性能的各种技术的文档 http www lua org gems sample pdf脚本代码 我很震惊竟然需要这样的技巧 虽然我引用的是 Lua 但我在 Javascript 中也见过类似的 hack 为什
  • 使用 EVAL、SCAN 和 DEL 的 Redis 通配符删除脚本返回“非确定性命令后不允许写入命令”

    因此 我正在寻求构建一个 lua 脚本 该脚本使用 SCAN 根据模式查找键并删除它们 原子地 我首先准备了以下脚本 local keys local done false local cursor 0 repeat local resul
  • LuaJit FFI 从 C 函数返回字符串到 Lua?

    假设我有这个 C 函数 declspec dllexport const char GetStr static char buff 32 Fill the buffer with some string here return buff 这
  • 十六进制常数 = 格式错误的数字?

    我有一个 Lua 脚本 我试图在其中使用十六进制数字 0x 如果我使用官方 Windows 二进制文件在控制台中运行此脚本 它可以正常工作 但是如果我在我的应用程序中运行它 简单的 dofile 我得到 malformed number n
  • Lua:冒号符号、“自我”和函数定义与调用

    我对定义 调用 Lua 函数时使用的冒号表示法感到非常困惑 我以为我已经明白了 直到我看到这段代码 function string PatternSafe str return str gsub pattern escape replace
  • 使用 corona sdk 验证电子邮件地址

    在我的项目中 有一个供用户填写详细信息的表单 其中有一个文本字段用于输入用户的电子邮件 ID 所以我需要在 corona 项目中验证该文本字段中的电子邮件 试试这个正则表达式 local email email protected cdn
  • 如何解密Lua字节码?

    早上好 我正在尝试破译 Moon 字节码 但我无法以任何方式 有人可以帮助我吗 我有这个 例如 code 27 76 117 97 81 0 1 4 4 4 8 0 如何将此字节码解密为文本 我已经在这里搜索 http www asciit
  • 什么时候适合使用Lua这样的嵌入式脚本语言

    我玩 魔兽世界 大约有两年了 我对用来编写插件的 Lua 很好奇 由于到目前为止我读到的有关 Lua 的内容都是 快 轻 和 这太棒了 所以我想知道如何以及何时使用它 您需要在系统中嵌入像 Lua 这样的脚本语言的典型情况是什么 当您需要最
  • 如何在 Lua 中实现 OO?

    Lua 没有内置对 OO 的支持 但它允许您自己构建它 您能否分享一些实现面向对象的方法 请为每个答案写一个例子 如果您有更多示例 请发布另一个答案 我喜欢将 OOP 视为容器 对象 内的数据封装以及可以使用该数据完成的操作子集 还有很多内
  • 在lua中组合两个函数

    我刚开始学习lua 所以我的要求可能是不可能的 现在 我有一个接受函数的方法 function adjust focused window fn local win window focusedwindow local winframe w
  • VB6 - Lua 集成

    我想知道是否有人有任何集成 Lua 和 VB6 的技巧 我正在运行一个小型在线角色扮演游戏 添加一些脚本会很棒 嗯 这是可行的 我曾经为 Lua 5 0 2 做过 但找不到文件 在您拥有的选项中 您可以 将 Lua 封装在公开 Lua AP
  • 去掉尾随零和小数点

    使用 Lua 我将数字格式化为可变位数并去掉尾随零 小数点 例如 string format precision f value gsub 0 1 gsub 值的类型为数字 正数 负数 整数 小数 所以任务已经解决了 但出于美学 教育和性能
  • 在Lua中获取前一天的日期

    谁能告诉我如何使用 Lua 获取 YYYY MM DD 格式的前一天日期 即 一个片段 它将返回运行当天的前一天的日期 Try print os date Y m d os time 24 60 60 严格来说 这只能保证在 POSIX 系
  • 比较 Lua 中的日期

    我有一个带有日期表的变量 如下所示 table day number 15 year number 2015 month number 2 如何获取当前日期与上述日期之间的天数 非常感谢 您可以使用os time 将表转换为秒并获取当前时间
  • 如何终止Lua脚本?

    如何终止 Lua 脚本 现在我在 exit 方面遇到问题 我不知道为什么 这更像是一个 Minecraft ComputerCraft 问题 因为它使用了包含的 API 这是我的代码 while true do if turtle dete
  • 如何让我的 add 命令找到第一个变量和第二个变量的值,然后将它们加在一起?

    vars values function open file lex file end function lex file local data io open file r for char in data lines do Print
  • 在 Awesome-wm 中为特定应用程序设置窗口布局

    如何配置很棒 以便它可以启动两个窗口对齐的新应用程序 如下所示 xxxxxxxxxx xxxxxxxxxx xxxxxxxxxx xxxxxxxxxx 其中 x 是 pidgin 中的对话窗口 是好友列表窗口 一般来说 我想指定右窗口的宽度
  • Lua中有状态迭代器和无状态迭代器的区别

    Lua中无状态和有状态迭代器有什么区别 请详细解释一下 什么时候需要使用无状态 什么时候需要使用另一种 我需要例子来理解这个概念 首先让我们就一个定义达成一致 在 Lua 中 迭代器是function 类似对象 每次调用时都会返回序列中的下
  • Lua 的标准(或最好支持的)大数(任意精度)库是什么?

    我正在处理大量无法四舍五入的数字 使用 Lua 的标准数学库 似乎没有方便的方法来保持精度超过某些内部限制 我还看到有几个库可以加载以处理大数字 http oss digirati com br luabignum http oss dig

随机推荐

  • android应用程序版本管理

    一 版本的主要功能说明 在应用程序的升级 维护策略中 版本是一个关键的组成部分 主要体现在以下几个方面中 1 用户需要了解在他们的设备上所安装的应用程序的版本的特定信息 以及已安装程序的升级版本可用的情况 2 其他应用程序 作为同一个套件中
  • AD20铺铜显示和隐藏的设置

    如果只想隐藏当前选中的铜皮 那么就选中对应需要隐藏的铜 然后鼠标右击 在弹出的对话框中选择 铺铜操作 隐藏选中铺铜 需要隐藏一部分铜皮 即打开铺铜管理器 选择菜单栏中 工具 铺铜 铺铜管理器 在弹出的铺铜管理器对话框中 想将哪些铜皮去进行隐
  • 招行卡中心服务端开发【已offer】

    流程 4 2投递简历 4 9笔试 4 15一面 4 22二面 4 28offer 笔试 卡中心笔试题量偏少 16道选择 两道编程 选择题范围很广 涉及了java c 设计模式 概率统计 信息论与编码 数据库 操作系统 计网等等等等知识点 编
  • C/C++ &与&&

    表示逻辑与的意思 即为and 当运算符两边的表达式的结果都为true时 整个运算结果才为true 否则 只要有一方为false 则结果为false 比如 12 23的结果就是1 12 1 的结果是1 123 0的结果就是0 还具有短路的功能
  • Gdb 调试核心已转存储-调试VINS-FUSION/ORB-SLAM

    GDB调试C 工程非ROS 1 通过运行可执行程序来进入gdb CMakeLists中的修改 SET CMAKE BUILD TYPE Debug SET CMAKE CXX FLAGS DEBUG ENV CXXFLAGS O0 Wall
  • 2023-05-29 Unity 2进制5——Excel配置表工具

    文章目录 一 Excel 读取操作 一 打开 Excel 表 二 获取单元格信息 二 Excel 表配置工具 一 基础知识 二 配置工具 三 演示步骤 1 ExcelTool 2 BinaryMgr 一 Excel 读取操作 一 打开 Ex
  • 推荐系统(3)——最经典的推荐算法(协同过滤算法原理部分)

    一 最经典的推荐算法 协同过滤推荐算法 Collaborative Filtering 算法思想 物以类聚 人以群分 基本的协同过滤推荐算法基于以下假设 跟你喜好相似的人喜欢的东西你也很有可能喜欢 基于用户的协同过滤推荐 User base
  • 思科模拟器:三层交换实现不同vlan间的通信(图文)

    我们实现不同vlan间通信不止有这一种办法 比如我们常用的单臂路由可以实现不同vlan间通信 我以前的博客也有发布 不会的可以关注一下以前的文章 但是他经常应用于中小企业他的缺陷有 1 单臂 为网络骨干链路 容易形成网络瓶颈 2 子接口依然
  • python 包、模块学习总结

    模块基础 1 基本概念 模块是最高级别的程序组织单元 它将程序代码和数据封装起来以便重用 从实际角度来看 模块往往对应于python程序文件 或是用外部语言如C Java或C 编写而成的扩展 每一个文件都是一个模块 并且模块导入其他模块之后
  • gitlab安装并汉化

    gitlab安装并汉化 准备工作 Gitlab安装包分2种gitlab ce gitlab ee gitlab为社区免费版本 gitlab ee为企业收费版本 在功能上没有太大的区别 应没有使用过与安装过 网也没有资料 只是在网查询到一篇文
  • git上传仓库内容超过100M解决方法git

    git上传仓库内容超过100M解决办法git 报错例如 原因是上传文件最大只能上传100M 所以这里要把太大的文件删除 然后重新提交git 操作步骤如下 1 先找到文件的具体路径 执行方法上述报错中有 参考 git rev list obj
  • vscode c++解决包含头文件红色波浪线问题

    安装c c 插件后 按ctrl shift p 点击打开了c cpp properties json文件 对其中的IncludePath进行编辑 示例如下 includePath workspaceFolder workspaceFolde
  • CAP理论

    CAP理论在互联网界有着广泛的知名度 知识稍微宽泛一点的工程师都会把其作为衡量系统设计的准则 大家都非常清楚地理解了CAP 任何分布式系统在可用性 一致性 分区容错性方面 不能兼得 最多只能得其二 因此 任何分布式系统的设计只是在三者中的不
  • 靶机练习 No.23 Vulnhub靶机DarkHole 2 .git信息泄露 .bash_history历史命令提权

    靶机练习 No 23 Vulnhub靶机DarkHole 2 0x00 环境准备 0x01 信息收集 步骤一 ip 探测 步骤二 端口扫描 0x02 漏洞挖掘 思路一 web漏洞挖掘 git信息收集 思路二 22ssh 爆破 步骤一 git
  • CentOS7 运维 - 系统基础优化大全

    CentOS7 运维 系统基础优化大全 一 更换Yum源 国内源地址 备份CentOS官方源 使用阿里yum源 使用本地yum源 使用清华yum源 推荐 二 防火墙 临时关闭防火墙 永久关闭防火墙 关闭SELinux 临时关闭 永久关闭 三
  • Linux下SVN操作常用命令

    1 检出 svn co http 路径 目录或文件的全路径 本地目录全路径 username 用户名 password 密码 svn co svn 路径 目录或文件的全路径 本地目录全路径 username 用户名 password 密码
  • FLUKE DSX-5000 CH线缆测试仪怎么升级到新国标

    FLUKE DSX 5000 CH线缆测试仪怎么升级新标准GB T50312 2016 下面山东朗坤小编带给您FLUKE DSX 5000 CH线缆测试仪升级带有新标准软件的整体步骤 一起来学习吧 升级到5 1之后必须使用Linkware9
  • 全网最全总结,有源码,期望、有效值、方差、相关系数、自相关函、互相关函数,还分不清吗

    原文来自公众号 工程师看海 1 期望 期望也就是平均值 是一个数值 反应的是随机变量平均取值的情况 期望也叫做加权平均 在信号中代表直流分量 当随机变量X满足均匀分布时 对一段长度为N的离散序列X x n n 0 1 2 N 1 其期望E
  • 深度学习-1.1卷积

    卷积是一种数学运算 教科书上一般定义 首先有两个函数函数 f g 然后这两个函数的卷积 f g 如下 连续形式 离散形式 1 先将函数g t 延y轴翻转为g t 这是 卷 的由来 2 其中n是卷积的参数 将g t 平移n个长度 变为g n
  • Lua调用C的动态库步骤及接口分析

    Lua调用C的动态库 C语言可以完成一些lua不好实现的功能 当程序主体使用lua完成时 便需要掌握该技巧调用C来帮助我们达到目的 通过调用C的动态库简化操作流程 大致流程如下 使用C语言编写方法提供给lua调用 将C文件打包成动态库 lu