LUA和C/C++交互
更新时间: 2026/02/09
在Gitcode上查看源码

LUA和C/C++交互

Lua和C/C++之间通信的主要主件是无处不在的虚拟栈,几乎所有的API调用都是操作这个栈中的值。

C/C++调用lua(表现Lua的嵌入式)

lua_pcall 是 Lua C API 中的一个函数,用于以保护模式调用 Lua 函数。在调用 Lua 函数时,如果发生了错误,lua_pcall 会捕获这个错误并返回错误码,而不会让程序直接崩溃。 ‘int lua_pcall(lua_State *L, int nargs, int nresults, int errfunc);’

  • lua_State *L 是表示 Lua 解释器状态的指针。
  • int nargs 是传递给 Lua 函数的参数个数。
  • int nresults 是期望从 Lua 函数中返回的结果个数。
  • int errfunc 是错误处理函数在栈中的索引(通常为 0 表示使用默认的错误处理函数)。

lua_pcall 的返回值是执行结果,如果执行成功返回 0,如果有错误则返回其他值,并且错误信息会被压入栈顶。

在调用lua_call函数之前,需要将函数本身和所有的参数依次压入Lua栈中。但是,对于栈上的元素来说,索引是从1开始的,而不是从0开始。所以,在lua_call函数中,第一个索引位置对应的是被调用的函数,而不是第二个1的索引位置。第二个1索引位置对应的是该函数的第一个参数。 举个例子,如果你有一个函数在Lua中定义为:

lua
function my_function(x, y)
    return x + y
end

在C中调用:

C
#include <lua.hpp>
#include <stdio.h>
int main() {
    lua_State* L = luaL_newstate();
    luaL_openlibs(L);

    // 加载和执行 Lua 脚本文件的步骤...
    lua_getglobal(L, "my_function");  // 将函数本身推入栈
    lua_pushinteger(L, 1);            // 将参数 x 推入栈
    lua_pushinteger(L, 2);            // 将参数 y 推入栈
    lua_pcall(L, 2, 1, 0);            // 调用函数,传入2个参数,期望返回1个结果
    // 获取返回值
    if (lua_isinteger(L, -1)) {
        int result = lua_tointeger(L, -1);
        printf("Result of my_function: %d\n", result);
    } else {
        printf("Error: result is not an integer.\n");
    }
    lua_pop(L, 1);  // 弹出返回值

    lua_close(L);
    return 0;
}

lua调用C/C++(表现Lua的可扩展性)

  • lua不可以调用所有C函数,只能调用遵循某种规则定义的C函数,lua调C时必须注册该函数,即以一种恰当的方式为lua提供c函数的地址。
  • lua调用C函数时,也使用了与C调用lua时相同类型的栈,C从栈中获取参数,并将结果压入栈中。但是这个栈不是全局结构,每一个函数都有其私有的局部栈。当lua调用C函数,第一个参数总是位于索引位置为1的位置。

C函数定义:

C
static int l_sin(lua_State *L){                                                          
    double d = luaL_checknumber(L, 1);   // 从虚拟栈中取出参数
    double res = sin(d);                              // 调用c/c++函数计算
    lua_pushnumber(L, res);                      // 将结果压入虚栈       
    return 1;                                               // 返回返回值个数
}

第一种调用方式:简单的独立解释器调用

C
c代码:
#include <stdio.h>
#include <string.h>
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#include <math.h>
        
static int l_sin(lua_State *L){                                     
    double d = luaL_checknumber(L, 1);   // 从虚拟栈中取出参数
    double res = asin(d);              // 调用c/c++函数计算
    lua_pushnumber(L, res);            // 将结果压入虚栈        
    return 1;                  // 返回返回值个数
}

int main(void){
    char buff[256];
    int error;
    lua_State *L=luaL_newstate();
    luaL_openlibs(L);
    lua_pushcfunction(L, l_sin);
    lua_setglobal(L, "mysin");
    error = luaL_dofile(L, "271.lua"); // Execute the Lua script file
    if (error) {
    fprintf(stderr, "Error executing script: %s\n", lua_tostring(L, -1));
    lua_pop(L, 1); // Pop the error message from the stack
    }
    lua_close(L);
    return 0;
}

lua调用脚本271.lua:
local angle = 0.5
local result = mysin(angle)
print("sin(" .. angle .. ") =", result)
注:其中lua脚本的路径是相对于执行时的路径。

第二种调用方式:将c函数注册到Lua环境中,作为库函数。把c函数编译成动态库,链接到lua环境中

C
库函数注册:
#include <stdio.h>
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#include <math.h>

static int l_sin(lua_State *L){
    double d = luaL_checknumber(L, 1);   // 从虚拟栈中取出参数
    double res = sin(d);           // 调用c/c++函数计算
    lua_pushnumber(L, res);            // 将结果压入虚栈        
    return 1;                    // 返回返回值个数
}

// 注册 C 函数到 Lua 环境中
static const struct luaL_Reg mylib[] = {
    {"l_sin", l_sin},  // 注册函数名为 l_sin
    {NULL, NULL}        // 结束标记
};
int luaopen_mylib(lua_State *L) {
    luaL_newlib(L, mylib);  // 创建新的 Lua 库并注册函数
    return 1;             // 返回创建的 Lua 库
}

lua调用:
    local mylib = require("mylib") 
    print(mylib.l_sin(3.14159))