2013-08-28 169 views
4

我打算用C語言實現一個函數,並且這個函數將被Lua腳本調用。如何使用作爲參數傳遞給lua C函數的表?

這個函數應該接收一個lua表作爲參數,所以我應該讀取表中的字段。我嘗試像下面這樣做,但是當我運行它時,我的函數崩潰。任何人都可以幫助我找到問題嗎?

 

/* 
function findImage(options) 
    imagePath = options.imagePath 
    fuzzy = options.fuzzy 
    ignoreColor = options.ignoreColor; 


end 

Call Example: 

    findImage {imagePath="/var/image.png", fuzzy=0.5, ignoreColor=0xffffff} 

*/ 


// implement the function by C language 
static int findImgProxy(lua_State *L) 
{ 
    luaL_checktype(L, 1, LUA_TTABLE); 

    lua_getfield(L, -1, "imagePath"); 
    if (!lua_isstring(L, -1)) { 
     error(); 
    } 
    const char * imagePath = lua_tostring(L, -2); 
    lua_pop(L, 1); 

    lua_getfield(L, -1, "fuzzy"); 
    if (!lua_isnumber(L, -1)) { 
     error(); 
    } 
    float fuzzy = lua_tonumber(L, -2); 

    lua_getfield(L, -1, "ignoreColor"); 
    if (!lua_isnumber(L, -2)) { 
     error(); 
    } 
    float ignoreColor = lua_tonumber(L, -2); 

    ... 

    return 1; 
} 
 

如何從C到Lua中返回一個表:

 

struct Point { 
    int x, y; 
} 
typedef Point Point; 


static int returnImageProxy(lua_State *L) 
{ 
    Point points[3] = {{11, 12}, {21, 22}, {31, 32}}; 

    lua_newtable(L); 

    for (int i = 0; i 3; i++) { 
     lua_newtable(L); 
     lua_pushnumber(L, points[i].x); 
     lua_rawseti(L, -2, 0); 
     lua_pushnumber(L, points[i].y); 
     lua_rawseti(L, -2, 1); 
     lua_settable(L,-3); 
    } 

    return 1; // I want to return a Lua table like :{{11, 12}, {21, 22}, {31, 32}} 
} 
 
+0

「*有問題*」*有什麼錯?你期望它做什麼,它在做什麼是不正確的? –

+0

我想在C函數中讀取lua表,但它崩潰了,我仍然在發現問題。所以我希望有人可以幫助我檢查我使用的方式是否正確。 – Suge

回答

12

當使用Lua的C API獲得舒適與虛擬堆棧的工作是很重要的工作 - 所有重要語言邊界交互發生在那裏。看你的代碼片段,它看起來並不像你在正確的編組數據C.

當寫你基本上有一個lua C函數做3兩件事:

  • 轉換輸入LUA數據轉換成可以在C中使用的東西。
  • 執行處理或任何功能需要執行的操作。
  • 轉換並返回輸出結果,如果有任何返回lua。

作爲一個例子,這裏是你的findImgProxy應該是什麼樣子:

static int findImgProxy(lua_State *L) 
{ 
    // discard any extra arguments passed in 
    lua_settop(L, 1); 
    luaL_checktype(L, 1, LUA_TTABLE); 

    // Now to get the data out of the table 
    // 'unpack' the table by putting the values onto 
    // the stack first. Then convert those stack values 
    // into an appropriate C type. 
    lua_getfield(L, 1, "imagePath"); 
    lua_getfield(L, 1, "fuzzy"); 
    lua_getfield(L, 1, "ignoreColor"); 
    // stack now has following: 
    // 1 = {imagePath="/var/image.png", fuzzy=0.5, ignoreColor=0xffffff} 
    // -3 = "/var/image.png" 
    // -2 = 0.5 
    // -1 = 0xffffff 

    const char *imagePath = luaL_checkstring(L, -3); 
    double fuzzy = luaL_checknumber(L, -2); 
    int ignoreColor = luaL_checkint(L, -1); 
    // we can pop fuzzy and ignoreColor off the stack 
    // since we got them by value 
    lua_pop(L, 2); 

    // do function processing 
    // ... 

    return 1; 
} 

請注意,我們必須在堆棧上保持imagePath因爲我們拿着const char *它。由於lua可能會收集該字符串,所以彈出該字符串將使*imagePath無效。

或者,您可以將由luaL_checkstring返回的字符串複製到另一個緩衝區中。在這種情況下關閉字符串是可以的,因爲我們不再指向lua擁有的內部緩衝區。

編輯:如果表中的某些鍵是可選的,您可以使用luaL_opt*函數來代替並提供默認值。例如,如果fuzzyignoreColor是可選的:

// ... 
    const char *imagePath = luaL_checkstring(L, -3); 
    double fuzzy = luaL_optnumber(L, -2, 0.0); // defaults to 0.0 if no fuzzy 
    int ignoreColor = luaL_optint(L, -1, 0);  // defaults to 0 if no ignoreColor 
    // ... 

因此,如果調用代碼爲密鑰提供了一個無意義的值,這仍然會產生一個錯誤。 OTOH,如果它不存在,則值爲nil,並使用提供的默認值。

+0

@ greatwolf非常感謝你,我從來沒有得到像你一樣清晰和有用的答案。一般我已經明白了。但是我還有一個問題,我應該從C函數返回一個表到lua,但是我的代碼上面添加)不起作用,你可以看看嗎?非常感謝。 – Suge

+0

如果參數表的鍵號不固定,表格可能是{imagePath =「/ var/q.png」}或者可能是{imagePath =「/ var/q.png」,fuzzy = 1.0}或者可能是{imagePath =「/ var/q.png」,ignoreColor = 0xffffff}。如何獲取值? – Suge

+0

@Suge如果某些鍵是可選的,你可以使用'luaL_opt *'函數來獲取它們。 – greatwolf

相關問題