2013-02-23 65 views
2

假設我有一個從C端擁有的指針,我希望以用戶數據的形式推入到Lua棧中。在不犧牲指定特定metatable的能力的情況下,完成此操作的最佳方法是什麼?Lua C API推送現有的指針

我最初的想法是使用一個light userdata,但是從我讀的here中,所有light userdatas都共享一個metatable。這是不可取的,因爲它會強制所有我的c面對象的共同行爲。

考慮到我希望爲Lua分配的對象重用元表,只需將一個不同的指針傳遞給元方法,我的第二個想法就是將一個人爲的指針附加到userdata對象。

struct ud 
{    
    struct T* ptr; 
    struct T data; 
}; 

struct ud* p = (struct ud*)lua_newuserdata(L, sizeof(struct ud)); 
p->ptr = &(p->data); 

或者,在推光用戶數據

struct T object; 
struct T** p = (struct T**)lua_newuserdata(L, sizeof(struct T*)); 
*p = &object; 

的情況下,附加該指針推薦的,還是有更多的API友好的替代?我的最終目標是簡單地將現有指針推送到Lua,並將元數據與它相關聯,以便metatable可以重複用於重和輕userdatas。

+1

你不能用'void *'s做指針運算。那麼你究竟想要你的第一個代碼示例要做什麼? – 2013-02-23 09:44:38

+0

這是我的錯誤。我忘記了void *上的指針算術是非標準的。目的是將這個指針附加到用戶數據,然後是結構本身。然後,將這個指針設置到它自己後面的位置,我期望結構被分配。我將編輯我的代碼,以標準方式反映出來。 – TheCodeBroski 2013-02-23 09:50:01

回答

1

一個常見的(但不是唯一的)方法是使用稱爲「盒裝指針」的技術。這個想法是,你分配一個足夠大的用戶數據來保存指針,然後將你的元數據等附加到它。

void push_pointer(lua_State *L, void *p) { 
    void **bp = lua_newuserdata(L, sizeof(p)); 
    *bp = p; 

    // setup metatable, etc 
} 

然後,通過元表調用的函數將得到棧上用戶數據,並從它拆開原來的指針。

// called via metatable 
int some_function(lua_State *L) { 
    assert(lua_type(L, 1) == LUA_TUSERDATA); 
    void **bp = lua_touserdata(L, 1); 
    void *p = *bp; 

    // do stuff with p 
} 

有一對夫婦的事情,你必須考慮這樣做時:

  • 對象的壽命。如果C端對象被釋放,而Lua端的某個對象具有對其userdate的引用,那麼你將有一個懸掛指針。如果這是可能發生的事情,那麼你需要一種方法來處理它。我自己通過擁有一個「實況」C對象的註冊表來處理這個問題,我可以在嘗試使用指針之前檢查它。

  • 用戶數據相等。由於您爲每個指針推送一個新的用戶數據,因此具有相同指針的兩個用戶數據在Lua中不會相等。如果這對你很重要,有幾種方法可以處理它。 metamethod是最容易的,但並不總是合適的。我已經使用了上面提到的同一個對象註冊表來提供一個pointer-> userdata映射,然後在推送的時候,如果我已經有了一個指針的userdata,我只是推它而不是創建一個新的。