跳到主要内容

C 语言调用 Lua

Lua 很适合嵌入到 C / C++ 程序中。你可以让 C 程序负责底层能力,例如设备访问、网络、图形渲染;再让 Lua 负责配置、业务逻辑或脚本扩展。

这一节带你写一个最小 C 程序:创建 Lua 虚拟机,加载标准库,执行 Lua 脚本,然后关闭虚拟机。

准备环境

在 Ubuntu / Debian 上,你通常需要安装 Lua 开发头文件和编译工具:

sudo apt install build-essential lua5.4 liblua5.4-dev pkg-config

不同系统上的包名可能不同。如果 pkg-config --libs lua5.4 找不到结果,请检查发行版提供的 Lua 开发包名称。

第一个嵌入式程序

创建 main.c

main.c
#include <stdio.h>

#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>

int main(void)
{
lua_State *L = luaL_newstate();
if (L == NULL) {
fprintf(stderr, "cannot create Lua state\n");
return 1;
}

luaL_openlibs(L);

if (luaL_dostring(L, "print('Hello from Lua')") != LUA_OK) {
fprintf(stderr, "lua error: %s\n", lua_tostring(L, -1));
lua_close(L);
return 1;
}

lua_close(L);
return 0;
}

编译:

cc main.c -o call_lua $(pkg-config --cflags --libs lua5.4)

运行:

./call_lua

输出:

Hello from Lua

执行 Lua 文件

创建 script.lua

script.lua
print("script is running")

修改 C 程序中的执行部分:

if (luaL_dofile(L, "script.lua") != LUA_OK) {
fprintf(stderr, "lua error: %s\n", lua_tostring(L, -1));
lua_close(L);
return 1;
}

luaL_dofile() 会加载并执行 Lua 文件。执行失败时,错误信息会留在 Lua stack 顶部。

C 调用 Lua 函数

创建 script.lua

script.lua
function add(a, b)
return a + b
end

C 程序:

call-function.c
#include <stdio.h>

#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>

int main(void)
{
lua_State *L = luaL_newstate();
luaL_openlibs(L);

if (luaL_dofile(L, "script.lua") != LUA_OK) {
fprintf(stderr, "%s\n", lua_tostring(L, -1));
lua_close(L);
return 1;
}

lua_getglobal(L, "add");
lua_pushinteger(L, 3);
lua_pushinteger(L, 5);

if (lua_pcall(L, 2, 1, 0) != LUA_OK) {
fprintf(stderr, "%s\n", lua_tostring(L, -1));
lua_close(L);
return 1;
}

lua_Integer result = lua_tointeger(L, -1);
lua_pop(L, 1);

printf("result: %lld\n", (long long)result);

lua_close(L);
return 0;
}

编译:

cc call-function.c -o call_function $(pkg-config --cflags --libs lua5.4)

运行:

./call_function

输出:

result: 8

Lua stack 的基本直觉

Lua C API 围绕一个虚拟 stack 工作:

  • C 通过 lua_push*() 把值压入 stack。
  • C 通过 lua_getglobal()lua_getfield() 等函数取 Lua 侧值。
  • C 通过 lua_pcall() 调用 Lua 函数。
  • C 通过 lua_to*() 从 stack 读取返回值。
  • 读完后要用 lua_pop() 清理不再需要的值。

初学 C API 时,最常见错误就是 stack 上的参数数量、返回值数量和索引搞错。

Lua 调用 C 函数

你也可以把 C 函数注册给 Lua 调用:

register-function.c
#include <stdio.h>

#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>

static int c_add(lua_State *L)
{
lua_Integer a = luaL_checkinteger(L, 1);
lua_Integer b = luaL_checkinteger(L, 2);

lua_pushinteger(L, a + b);
return 1;
}

int main(void)
{
lua_State *L = luaL_newstate();
luaL_openlibs(L);

lua_register(L, "c_add", c_add);

if (luaL_dostring(L, "print(c_add(10, 20))") != LUA_OK) {
fprintf(stderr, "%s\n", lua_tostring(L, -1));
}

lua_close(L);
return 0;
}

输出:

30

c_add() 返回 1,表示它向 Lua 返回了一个值。

小结

你需要掌握:

  • luaL_newstate() 创建 Lua state。
  • luaL_openlibs() 打开标准库。
  • luaL_dostring() 执行字符串代码。
  • luaL_dofile() 执行 Lua 文件。
  • lua_pcall() 用于安全调用 Lua 函数。
  • Lua C API 通过 stack 交换参数和返回值。
  • C 函数返回给 Lua 的值数量由 C 函数的返回值指定。