Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

从 Lua 调用 C

将 C 函数暴露给 Lua 是扩展 Lua 的主要方式。这允许你用 C/C++ 编写高性能模块,供 Lua 脚本调用。

C 函数原型

所有可被 Lua 调用的 C 函数必须符合以下签名:

int my_c_function(lua_State *L);
  • 参数通过栈传递,lua_gettop(L) 可获取参数个数
  • 返回值通过压栈实现,return n 表示返回 n 个值

最小示例

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;       // 1 个返回值 
}

注册到 Lua

方式一:注册为全局函数

lua_pushcfunction(L, c_add);
lua_setglobal(L, "c_add");   // Lua 中可直接调用 c_add(1,2) 

方式二:组织为模块(推荐)

使用 luaL_Reg 数组批量注册:

static const struct luaL_Reg mylib[] = {
    {"add", c_add},
    {"sub", c_sub},
    {NULL, NULL}        // 哨兵,必须以此结尾
};

// luaL_newlib 内部会创建 table 并把函数填入(第 5 章会讲 table)
int luaopen_mylib(lua_State *L) {
    luaL_newlib(L, mylib);
    return 1;                    // 返回 table
}

在 Lua 中:

local mylib = require("mylib")
print(mylib.add(10, 20))

对于 require 能正确找到 luaopen_mylib,通常需要将 C 代码编译为共享库(.so / .dll),并放入 Lua 的 package.cpath 搜索路径。第 19 章会讲标准库加载和模块搜索机制。

完整代码


#include <assert.h>
#include <lauxlib.h>
#include <lua.h>
#include <lualib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.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;
}

static int c_reverse(lua_State *L) {
    size_t len;
    const char *s = luaL_checklstring(L, 1, &len);

    char *buf = malloc(len);
    for (size_t i = 0; i < len; i++)
        buf[i] = s[len - 1 - i];

    lua_pushlstring(L, buf, len);
    free(buf);
    return 1;
}

static int c_sum(lua_State *L) {
    int n = lua_gettop(L);
    lua_Number sum = 0;
    for (int i = 1; i <= n; i++) {
        sum += luaL_checknumber(L, i);
    }
    lua_pushnumber(L, sum);
    return 1;
}

static const struct luaL_Reg mylib[] = {
    {"add", c_add}, {"reverse", c_reverse}, {"sum", c_sum}, {NULL, NULL}};

int luaopen_mylib(lua_State *L) {
    luaL_newlib(L, mylib);
    return 1;
}

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

    lua_pushcfunction(L, c_add);
    lua_setglobal(L, "g_add");

    luaopen_mylib(L);
    lua_setglobal(L, "mylib");

    const char *script =
        "print('mylib.add(3,4) =', mylib.add(3, 4))\n"
        "print('mylib.reverse(\"abc\") =', mylib.reverse('abc'))\n"
        "print('mylib.sum(1,2,3,4) =', mylib.sum(1, 2, 3, 4))\n"
        "print('g_add(10,20) =', g_add(10, 20))\n";

    luaL_dostring(L, script);

    lua_close(L);
    puts("04-call-c: ok");
    return 0;
}