【Lua】Windows 下编写 C 扩展模块:VS 编译与 Lua 调用全流程

▒ 目录 ▒

    • 🛫 导读
      • 需求
      • 环境
    • 1️⃣ 核心原理:Windows下Lua与C的交互逻辑
    • 2️⃣ Windows下编写步骤:以`mymath`模块为例
      • 2.1 步骤1:准备Windows开发环境
        • 方式1:官网下载Lua源码并编译(可控性高)
        • 方式2:使用sourceforge下载编译好的项目(新手友好,免编译)
      • 2.2 步骤2:编写`mymath`模块的C代码
      • 2.3 步骤3:编译为Windows动态链接库(DLL)
      • 2.4 步骤4:在Windows下的Lua中调用模块
        • 步骤1:配置DLL路径(二选一)
        • 步骤2:编写Lua脚本调用模块
        • 步骤3:执行脚本
    • 3️⃣ Windows下关键技术点与避坑指南
      • 3.1 栈操作核心规则(避免Lua虚拟机崩溃)
      • 3.2 Windows下常见编译错误与解决
    • 🛬 文章小结

🛫 导读

需求

在Windows环境下,通过Lua C扩展模块实现“高性能C代码与Lua脚本集成”(如封装Windows API、硬件接口),但常面临“开发环境配置复杂”、“编译工具选择(MinGW/Visual Studio)”、“动态库加载路径”等问题。

本文聚焦Windows平台,提供从“Lua开发库准备”、“C模块代码编写”、“VS编译”到“Lua调用”的全流程方案,以mymath模块为例(含加法、幂运算功能),帮助开发者快速掌握Windows下Lua C扩展的核心能力。

环境

版本号描述
文章日期2025-09-13
操作系统Win11
IDEVS2019
软件位数x86
lua5.1.5

1️⃣ 核心原理:Windows下Lua与C的交互逻辑

Lua通过C API(定义于lua.hlauxlib.h)实现与C代码的交互,核心依赖栈(stack)动态链接库(DLL),Windows环境下的关键逻辑如下:

  1. 数据传递:C与Lua的所有参数、返回值均通过“栈”交互(C向栈推数据供Lua使用,从栈取Lua传入的参数);
  2. 模块形式:C扩展需编译为*.dll(Windows动态链接库),文件名需与模块名一致(如mymath.dll对应模块mymath);
  3. 加载入口:模块必须包含固定命名的入口函数luaopen_模块名(如luaopen_mymath),Lua通过require加载DLL时自动调用该函数,完成C函数向Lua的注册。

2️⃣ Windows下编写步骤:以mymath模块为例

实现mymath模块,包含两个功能:add(a,b)(计算两数之和)、pow(a,b)(计算ab次方),全程基于Windows环境操作。

2.1 步骤1:准备Windows开发环境

需先获取Lua开发库(含lua.h等头文件和lua5x.lib链接库),Windows下推荐两种方式:

方式1:官网下载Lua源码并编译(可控性高)
  1. 下载Lua源码:访问Lua官网,下载Windows源码包(如lua-5.1.5.tar.gz);

  2. 解压源码至无空格目录(如${PRO_DIR});

  3. 编译Lua开发库:

    • 若用MinGW:打开MinGW终端,进入源码src目录,执行mingw32-make PLAT=mingw,生成lua5.1.lib(链接库)、lua5.1.dll(动态库)及lua.h(头文件,位于src目录);
    • 若用Visual Studio:打开VS命令提示符(如“x86 Native Tools Command Prompt for VS 2019”),进入源码src目录,执行nmake /f Makefile.win,生成lua5.1.liblua5.1.dll
  4. 整理开发文件:创建${PRO_DIR}目录,按如下结构存放(便于后续编译引用):

    ${PRO_DIR}\
    ├─ include\lua5.1\  # 头文件
    │  ├─ lua.h
    │  ├─ lauxlib.h
    │  └─ luaconf.h
    └─ lib\      # 链接库├─ lua5.1.lib(32位,2019,静态)└─ lua5.1.dll(非静态需要dll)
    
方式2:使用sourceforge下载编译好的项目(新手友好,免编译)
  1. 打开https://sourceforge.net/projects/luabinaries/files/5.1.5/Windows%20Libraries/Static/;

  2. 找到合适的版本(32位,2019,静态);
    在这里插入图片描述

  3. 将解压出来的文件拷贝到项目中,按照下面目录组织。
    在这里插入图片描述

2.2 步骤2:编写mymath模块的C代码

新建一个dll项目

创建mymath.c文件,完整代码如下(包含函数实现、注册逻辑):

#include "pch.h"  // 预编译头(可选)
#include <cmath>  // 引入C++标准库(用于数学计算)// 引入Lua C API头文件(路径需与实际开发库一致)
extern "C" {
#include ".\include\lua5.1\lua.h"
#include ".\include\lua5.1\lualib.h"
#include ".\include\lua5.1\lauxlib.h"#pragma comment(lib, "./lib/lua5.1.lib")// 1. 实现add函数:计算a + b(C函数与Lua的交互通过栈)
static int l_mymath_add(lua_State* L) {// 从栈取第1个参数(Lua传入的a),自动检查是否为数字,非数字则抛错double a = luaL_checknumber(L, 1);// 从栈取第2个参数(Lua传入的b)double b = luaL_checknumber(L, 2);// 将计算结果压入栈(作为返回值,栈顶为第1个返回值)lua_pushnumber(L, a + b);return 1;  // 返回值数量:1个
}// 2. 实现pow函数:计算a^b
static int l_mymath_pow(lua_State* L) {double a = luaL_checknumber(L, 1);double b = luaL_checknumber(L, 2);// 调用C标准库的pow函数计算double result = pow(a, b);lua_pushnumber(L, result);return 1;
}// 3. 定义函数列表:关联“Lua中函数名”与“C函数指针”
static const luaL_Reg mymath_funcs[] = {{"add", l_mymath_add},  // Lua调用mymath.add时,执行l_mymath_add{"pow", l_mymath_pow},  // Lua调用mymath.pow时,执行l_mymath_pow{NULL, NULL}            // 结束标记(不可省略)
};// 4. 模块入口函数:固定命名为luaopen_模块名(mymath)
__declspec(dllexport) int luaopen_mymath(lua_State* L) {// 创建新的Lua表,将mymath_funcs中的函数注册到表中luaL_register(L, "mymath", mymath_funcs);return 1;  // 返回注册好的函数表(Lua通过require获取该表)
}
}

2.3 步骤3:编译为Windows动态链接库(DLL)

Windows下用Visual Studio工具编译,需确保编译的DLL位数(32位)与Lua位数一致。

2.4 步骤4:在Windows下的Lua中调用模块

编译生成mymath.dll后,需确保DLL能被Lua找到,再通过require加载:

步骤1:配置DLL路径(二选一)
  • 简单方式:将mymath.dll与Lua.exe放在同一目录;
  • 通用方式:将mymath.dll所在目录添加到Windows系统环境变量PATH中(添加后需重启命令提示符)。
步骤2:编写Lua脚本调用模块

创建test.lua文件,内容如下:

-- 加载mymath模块(自动查找mymath.dll)
local mymath = require("mymath")-- 调用模块中的函数
print("2 + 3 =", mymath.add(2, 3))    -- 输出:2 + 3 = 5.0
print("2^10 =", mymath.pow(2, 10))    -- 输出:2^10 = 1024.0
print("3.5^2 =", mymath.pow(3.5, 2))  -- 输出:3.5^2 = 12.25
步骤3:执行脚本

打开Windows命令提示符,进入test.lua所在目录,执行:

lua test.lua

若输出正确结果,说明Windows下Lua C扩展模块调用成功。
在这里插入图片描述

ps: 也可以直接通过lua.exe,交互式调用
在这里插入图片描述

3️⃣ Windows下关键技术点与避坑指南

3.1 栈操作核心规则(避免Lua虚拟机崩溃)

Windows下Lua C API的栈操作与其他平台一致,但需严格遵守“栈平衡”:

  • 入栈数量 ≤ 出栈处理数量:每个C函数中,推到栈的返回值数量需与return后的数字一致(如return 1表示栈顶有1个返回值);
  • 参数索引正确性:Lua传入C的参数按顺序压栈,第1个参数索引为1,第2个为2(不可用负数索引操作参数,易混淆栈顶位置)。

3.2 Windows下常见编译错误与解决

错误现象原因解决方法
fatal error: lua.h: No such file or directory头文件路径错误/I后的路径是否正确,确保lua.h存在
undefined reference to 'luaL_newlib'Lua版本不兼容(luaL_newlib是Lua 5.2+新增)若为Lua 5.1,将luaL_newlib(L, funcs)改为luaL_register(L, "mymath", funcs)
无法找到lua5.1.lib链接库路径错误或位数不匹配确认-L//LIBPATH路径正确,且lua5.1.lib位数(32/64)与编译目标一致
Lua加载时提示“找不到指定的模块”DLL路径未配置或位数不匹配将DLL放入脚本目录或添加到PATH,确保DLL位数与Lua位数一致
LINK2019 _luaL_register#pragma comment(lib, "./lib/lua5.1.lib") 写成#pragma (lib, "./lib/lua5.1.lib")
LINK2019 luaL_checknumber未指定C引入 extern "C" {

在这里插入图片描述

🛬 文章小结

  1. Windows核心流程:准备Lua开发库(源码编译/ sourceforge下载)→ 编写C代码(含函数实现与入口函数)→ 用VS编译为DLL(确保位数匹配)→ 配置DLL路径→ Lua调用;
  2. 关键避坑点:DLL位数与Lua一致、头文件/链接库路径正确、DLL放入PATH或脚本目录、Lua版本与API兼容(如luaL_newlibvsluaL_register);
  3. 价值:Windows下通过Lua C扩展,可封装Windows API(如文件操作、系统信息)或高性能C逻辑,弥补Lua在底层操作的性能短板。

📖 参考资料

  • lua源码下载地址: https://lua.org/ftp/
  • lua 静态库下载地址: https://sourceforge.net/projects/luabinaries/files/5.1.5/Windows%20Libraries/Static/

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

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

相关文章

Python快速入门专业版(二十九):函数返回值:多返回值、None与函数嵌套调用

目录引一、多返回值&#xff1a;一次返回多个结果的优雅方式1. 多返回值的本质&#xff1a;隐式封装为元组示例1&#xff1a;返回多个值的函数及接收方式2. 多返回值的接收技巧技巧1&#xff1a;用下划线_忽略不需要的返回值技巧2&#xff1a;用*接收剩余值&#xff08;Python …

python使用pip安装的包与卸载

1&#xff1a;基本卸载命令 # 卸载单个包 pip uninstall package_name# 示例&#xff1a;卸载requests包 pip uninstall requests2&#xff1a;卸载多个包 # 一次性卸载多个包 pip uninstall package1 package2 package3# 示例 pip uninstall requests numpy pandas3&#xff1…

超级流水线和标量流水线的原理

一、什么是流水线&#xff1f;要理解这两个概念&#xff0c;首先要明白流水线&#xff08;Pipelining&#xff09; 的基本思想。想象一个汽车装配工厂&#xff1a;* 没有流水线&#xff1a;一个工人负责组装一整辆汽车&#xff0c;装完一辆再装下一辆。效率很低。* 有了流水线&…

【Ansible】管理复杂的Play和Playbook知识点

1.什么是主机模式&#xff1f;答&#xff1a;主机模式是Ansible中用于从Inventory中筛选目标主机的规则&#xff0c;通过灵活的模式定义可精准定位需要执行任务的主机。2.主机模式的作用答&#xff1a;筛选目标&#xff1a;从主机清单中选择一个或多个主机/组&#xff0c;作为P…

FastGPT源码解析 Agent 智能体应用创建流程和代码分析

FastGPT对话智能体创建流程和代码分析 平台作为agent平台&#xff0c;平台所有功能都是围绕Agent创建和使用为核心的。平台整合各种基础能力&#xff0c;如大模型、知识库、工作流、插件等模块&#xff0c;通过可视化&#xff0c;在界面上创建智能体&#xff0c;使用全部基础能…

缺失数据处理全指南:方法、案例与最佳实践

如何处理缺失数据&#xff1a;方法、案例与最佳实践 1. 引言 在数据分析和机器学习中&#xff0c;缺失数据是一个普遍存在的问题。如何处理缺失值&#xff0c;往往直接影响到后续分析和建模的效果。处理不当&#xff0c;不仅会浪费数据&#xff0c;还可能导致模型预测结果的不准…

为什么Cesium不使用vue或者react,而是 保留 Knockout

1. Knockout-ES5 插件的语法简化优势 自动深度监听&#xff1a;Cesium 通过集成 Knockout-ES5 插件&#xff0c;允许开发者直接使用普通变量语法&#xff08;如 viewModel.property newValue&#xff09;替代繁琐的 observable() 包装&#xff0c;无需手动声明每个可观察属性。…

Word怎么设置页码总页数不包含封面和目录页

有时候使用页码格式是[第x页/共x页]或[x/x]时会遇到word总页数和实际想要的页数不一致&#xff0c;导致显示不统一&#xff0c;这里介绍一个简单的办法&#xff0c;适用于比较简单的情况。 一、wps版本 文章分节 首先将目录页与正文页进行分节&#xff1a;在目录页后面选择插入…

突破机器人通讯架构瓶颈,CAN/FD、高速485、EtherCAT,哪种总线才是最优解?

引言&#xff1a; 从协作机械臂到人形机器人&#xff0c;一文拆解主流总线技术选型困局 在机器人技术飞速发展的今天&#xff0c;从工厂流水线上的协作机械臂到科技展会上的人形机器人&#xff0c;它们的“神经系统”——通讯总线&#xff0c;正面临着前所未有的挑战。特斯拉O…

Java核心概念详解:JVM、JRE、JDK、Java SE、Java EE (Jakarta EE)

1. Java是什么&#xff1f; Java首先是一种编程语言。它拥有特定的语法、关键字和结构&#xff0c;开发者可以用它来编写指令&#xff0c;让计算机执行任务。核心特点&#xff1a; Java最著名的特点是“一次编写&#xff0c;到处运行”&#xff08;Write Once, Run Anywhere - …

OSPF高级技术 相关知识点

1.多区域OSPFospf 设计多区域原因&#xff1a;① 每个区域的路由器只需同步自己所在区域的链路状态数据库&#xff0c;分区域设 计可以使得每个区域的链路状态数据库得以减少。以降低路由器cpu、内存 的消耗。② 避免某区域内的网络故障&#xff08;例如&#xff1a;接口频繁up…

Linux / Windows 下连续发送多帧 8 字节指令,下位机只响应第一帧,第二帧“丢失”。

串口编程易错点笔记 基于 serial::Serial&#xff08;wjwwood serial 库&#xff09; 场景&#xff1a;Linux / Windows 下连续发送多帧 8 字节指令&#xff0c;下位机只响应第一帧&#xff0c;第二帧“丢失”。1. 现象 serial::Serial ser("/dev/ttyUSB0", 115200);…

三十九、案例-配置文件-参数配置化(了解即可,现在主流使用yml配置文件)

参数配置化-问题引出参数配置化-问题解决参数配置化-代码与过程解析代码&#xff1a; AliOSSUtils&#xff08;工具类&#xff09; package com.itheima.utils;import com.aliyun.oss.OSS; import com.aliyun.oss.OSSClientBuilder; import org.springframework.beans.factory.…

Linux之virtio实现原理--pci 基础

一、概述 virtio设备可以基于不同总线来实现&#xff0c;本文介绍基于pci实现的virtio-pci设备。以virtio-blk为例&#xff0c;首先介绍PCI配置空间内容&#xff0c;virtio-pci实现的硬件基础——capability&#xff0c;最后分析PIC设备的初始化以及virtio-pci设备的初始化。 …

Claude-Flow AI协同开发:从“CTO”到“人机共生体”的AI协同开发

6.1 思维的终极融合&#xff1a;从“CTO”到“人机共生体” (Human-AI Symbiote) 在之前的章节中&#xff0c;我们逐步将您的角色从“开发者”提升为“项目经理”&#xff0c;最终定位为整个“人机混合团队的CTO”。这个模型强调的是一种 “指挥-控制” (Command-and-Control) …

TCGA单癌肿按单基因高低分组的转录组差异热图分析作图教程

TCGA单癌肿按单基因高低分组的转录组差异热图分析作图教程分析作图原理过程提取出TCGA中指定的单基因单癌肿的转录组表达数据对该单基因的表达水平的中位数作为阈值把样本分成高表达组和低表达组按该基因的高低表达样本分组来做该癌症的转录组差异分析对差异分析结果中top差异高…

手搓Tomcat

目录 Tomcat是什么&#xff1f; 前置工作准备 构建并启动Tomcat 处理Socket逻辑顺序 获取输入流并读取数据封装到Request 自定义Servlet对象 暂存响应体 按Http协议发送响应数据 部署Tomcat ​ Tomcat是什么&#xff1f; Tomcat 是一个 Web 应用服务器&#xff08;准确…

Linux网络:初识网络

文章目录1. 网络发展1.1 独立模式1.2 网络互联1.3 局域网LAN1.4 广域网WAN2. 认识 “协议”2.1 什么是协议&#xff1f;2.2 为什么要有协议&#xff1f;2.3 深入了解协议序&#xff1a;开网络之篇章&#xff0c;建网络之基础&#xff0c;将近2月过去&#xff0c;暑假期间不曾有…

文件检查与拷贝-简化版

本篇继续来学习shell脚本&#xff0c;对上一篇的文件检查与拷贝脚本进行简化修改。 1 功能说明 在Linux系统中&#xff0c;通过一个shell脚本&#xff0c;实现将一个目录中的所有文件&#xff08;包括子目录中的&#xff09;&#xff0c;拷贝到顶一个指定的目录&#xff0c;要求…

DCA1000 AWR1843 环境安装

mmWaveStudio GUI设计用于表征和评估TI Radar器械。mmWaveStudio通过SPI向mmWave设备发送命令来配置和控制mmWave设备。使用DCA 1000 EVM或TSW 1400 EVM板捕获ADC数据&#xff0c;并在Matlab中处理数据&#xff0c;结果显示在GUI中。mmWaveStudio GUI利用C DLL和一组API通过FTD…