1. 程式人生 > >lua 和 C 語言進行互動 —— 如何傳遞table

lua 和 C 語言進行互動 —— 如何傳遞table

方法1:

採用 lua_pushstring/lua_pushnumber 傳遞key、value,然後通過 lua_settable 設定 table 中的kv對,like this:
        lua_pushnumber(L, 1);
        lua_pushstring(L, "value1");
        lua_settable(L, -3);
其中“lua_settable(L, -3)”表示將前壓棧中的前兩個引數作為一個kv對放到table中。

1. 首先編寫 lua 檔案 lua_test.lua:

-- file: lua_test.lua
function domain(i)

    -- call C function.
    local tab = gettab() 

    -- show key and value
    for k, v in pairs(tab) do
        print("key: ".. k)
        print("val: ".. v)
	print()
    end

end

2. 其中 gettab 是 C 中註冊的函式,下面是對應的 C 程式碼 c_test.c :

/*
 * file: c_test.c
 */
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>

int get_tab(lua_State *L)
{
    /* create table. */
    lua_newtable(L);

    /* push (key, value). */
    int i;
    char value[10] = {0};
    for(i=0; i<5; ++i)
    {
        sprintf(value, "value%d", i+1);
        lua_pushnumber(L, i+1);    //key
        lua_pushstring(L, value);  //value
        lua_settable(L, -3);       //push key,value
    }

    /* deal return. */
    return 1;
}

int main()
{
    /* create a state and load standard library. */
    lua_State* L = luaL_newstate();

    /* opens all standard Lua libraries into the given state. */
    luaL_openlibs(L);

    /* register function be called by lua. */
    lua_register(L, "gettab", get_tab);

    /* load and exec the specified lua file. */
    int error = luaL_dofile(L, "lua_test.lua");
    if(error) {
        perror("luaL_dofile error");
        exit(1);
    }

    /* get the domain function from lua file. */ 
    lua_getglobal(L,"domain");

    /* exec the domain function. */
    error = lua_pcall(L, 0, 0, 0);
    if (error) {
        fprintf(stderr,"%s\n",lua_tostring(L,-1));
        lua_pop(L,1);
    }

    /* close lua state. */
    lua_close(L);

    return 0;
}
使用一下命令編譯:
gcc c_test.c -I/usr/local/include/luajit-2.0 -L/usr/local/lib -lluajit-5.1 -o exe
note:環境需要裝luajit

3. 下面執行編譯出來的可執行檔案 exe:

key: 1
val: value1

key: 2
val: value2

key: 3
val: value3

key: 4
val: value4

key: 5
val: value5


方法2:

上面對 table 的 kv 對是這樣處理的:
        lua_pushnumber(L, i+1);    //key
        lua_pushstring(L, value);  //value
        lua_settable(L, -3);       //push key,value
其實有一種效率高的方法,like this:
        lua_pushstring(L, value);
        lua_rawseti(L, -2, i++);

最後再寫一種 lua 呼叫函式庫的方法:

1. 首先編寫 C 檔案 so_test.c:

/* 
 * file:so_test.c
 */
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#include <stdio.h>

int get_tab(lua_State *L)
{
    /* get the input. */
    int num = lua_tonumber(L, 1);

    /* create table. */
    lua_newtable(L);

    /* push (key, value). */
    int i;
    char value[10] = {0};
    for(i=0; i<num; ++i)
    {
        sprintf(value, "value%d", i+1);
        lua_pushnumber(L, i+1);
        lua_pushstring(L, value);
        lua_settable(L, -3);
    }

    /* deal return. */
    return 1;
}

static const luaL_Reg mylib[] = {
    {"get_tab", get_tab},
    {NULL, NULL}
};

int luaopen_lua_test(lua_State *L) {
    luaL_register(L, "lua_test", mylib);
    return 0;
}
用以下命令編譯出動態庫 lua_test.so:
gcc so_test.c -shared -fPIC -I/usr/local/include/luajit-2.0/ -I/usr/include/ -lluajit-5.1 -o lua_test.so

2. 然後編寫 lua 測試程式碼 test.lua:

-- file: test.lua
local test = require('lua_test')

function domain(num)

    -- call C function.
    local tab = test.get_tab(num) 

    -- show key and value
    for k, v in pairs(tab) do
        print("key: ".. k)
        print("val: ".. v)
	print()
    end

end

domain(5)

3. 執行 lua 程式碼:

# lua test.lua 
key: 1
val: value1

key: 2
val: value2

key: 3
val: value3

key: 4
val: value4

key: 5
val: value5

以上程式碼的編譯執行環境:

os:CentOS release 6.4 (Final)

gcc:gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-3)

lua:Lua 5.1.4

luajit:LuaJIT 2.0.2

參考書:Programming in Lua