Lua的扩展与应用
Lua 是一种轻量级脚本语言,扩展性好,最常见的扩展对象是 C/C++。这一组文档覆盖三个方向:与 C 语言的交互、嵌入式开发和 LuaJIT。
1. C与Lua的交互
Lua 与 C 集成得很深:C 可以调用 Lua,Lua 也可以调用 C,两条路用的都是 Lua C API,也就是一组在 C 代码里操作 Lua 状态的 C 函数。所谓 C 扩展,就是用这套 API 写 C 代码给 Lua 加功能,或者把热点逻辑挪到 C 里跑。
一个最小的 C 扩展:
c
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
// C函数:计算两个数的和
static int l_sum(lua_State *L) {
// 获取参数
lua_Integer a = luaL_checkinteger(L, 1);
lua_Integer b = luaL_checkinteger(L, 2);
// 计算和并推入栈
lua_pushinteger(L, a + b);
// 返回结果的数量
return 1;
}
// 模块函数表
static const luaL_Reg mylib_funcs[] = {
{"sum", l_sum},
{NULL, NULL}
};
// 模块入口:require("mylib") 时由 Lua 自动调用
int luaopen_mylib(lua_State *L) {
luaL_newlib(L, mylib_funcs); // 创建模块表并注册函数
return 1; // 返回模块表
}几个关键点:
luaL_checkinteger用于获取传递给C函数的参数。lua_pushinteger用于将结果推送到Lua栈。luaopen_mylib是模块入口:require("mylib")会调用它,并把它的返回值作为模块本身。因此必须在这里创建模块表(luaL_newlib)并返回 1 个值;如果只是用lua_register把函数注册成全局函数而不返回表,require("mylib")得到的将是true,随后的mylib.sum(...)就会报错。
编译和使用:
使用
gcc编译 C 扩展为动态库(头文件路径按本机 Lua 安装位置调整):shgcc -shared -fPIC -o mylib.so mylib.c -I/usr/local/include在 Lua 脚本中调用
require来加载动态库,并使用注册的 C 函数。
lua
-- Lua脚本
local mylib = require("mylib")
print(mylib.sum(10, 20)) -- 输出 302. 嵌入式开发
Lua 的代码和内存开销小,执行也不慢,所以常被嵌进资源受限的环境。常见的用法:游戏引擎用它写游戏逻辑,路由器和交换机用它做配置和自动化任务,应用程序拿它做插件系统,让用户用脚本扩展功能。
在 C 程序里嵌一段执行脚本的逻辑,只需要几行:
c
#include <stdio.h>
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
void run_lua_script(const char *script) {
lua_State *L = luaL_newstate(); // 创建Lua状态
luaL_openlibs(L); // 打开Lua标准库
if (luaL_dofile(L, script) != LUA_OK) {
fprintf(stderr, "Error: %s\n", lua_tostring(L, -1));
}
lua_close(L); // 关闭Lua状态
}三个调用:
luaL_newstate创建一个新的Lua状态。luaL_openlibs打开Lua的标准库。luaL_dofile执行Lua脚本文件。
3. LuaJIT
LuaJIT 是 Lua 的高性能实现,比标准解释器跑得快,功能也更多。它有两样标准 Lua 没有的东西:一是 JIT 编译器,把 Lua 字节码编译成机器码;二是 FFI 库,让 Lua 直接调用 C 函数、使用 C 数据结构,不用写 C 扩展。
用 FFI 调一个 C 函数:
lua
local ffi = require("ffi")
-- 定义C函数
ffi.cdef[[
int add(int a, int b);
]]
-- 加载C库
local mylib = ffi.load("mylib")
-- 调用C函数
print(mylib.add(10, 20)) -- 输出 30这段脚本里:
ffi.cdef用于声明C函数。ffi.load加载C动态库。- 直接调用C函数而无需编写C扩展。