LuaTinker的bug和缺陷

來源:互聯網
上載者:User

標籤:lua   luatinker   模板   c++   

LuaTinker的bug和缺陷

LuaTinker是一套還不錯的C++代碼和Lua代碼的綁定庫,作者是韓國人Kwon-il Lee,作者應該是參考了LuaBind後,為了簡化和避免過重而實現的。其官網在http://gpgstudy.com/gpgiki/LuaTinker ,但可惜全部是韓文的,而最新的代碼可以在Git上下載,https://github.com/zupet/LuaTinker 。對比LuaBind,LuaPlus這類庫,其實現非常非常非常非常非常輕,大約只有1000多行,至少給了你一個機會,去瞭解和改寫部分功能,所以其在國內也有不少群眾基礎。而且其輕薄的身材也讓剖析一下一個指令碼粘合層是如何工作成為了可能。

但另外一方面LuaTinker的bug數量並不在少數。也有不少同學曾經零散的提出來過。這兒只是做個總結,另外感謝fergzhang同學。很多問題都是他幫忙指出的。

  1. BUG(錯誤)

第一個問題,int64_t 資料的比較是錯誤的,完全沒有考慮符號位的情況嘛。

static int lt_s64(lua_State *L){     //完全沒有考慮符號位的情況,居然用memcmp    lua_pushboolean(L, memcmp(lua_topointer(L, 1), lua_topointer(L, 2), sizeof(long long)) < 0);    return 1;}

 

第二個問題,在處理類成員的修改函數(__newindex)時,沒有考慮要處理父類成員的,而LuaTinker是支援繼承的,而且int lua_tinker::meta_get(lua_State *L) (對應__index)也是支援。這應該是作者的一個疏漏。

int lua_tinker::meta_set(lua_State *L){    enum_stack(L);    lua_getmetatable(L, 1);    lua_pushvalue(L, 2);    lua_rawget(L, -2);    enum_stack(L);    if (lua_isuserdata(L, -1))    {        user2type<var_base *>::invoke(L, -1)->set(L);}    else if (lua_isnil(L, -1)){    //這兒沒有調用invoke_parent(L)處理父類的情況        lua_pushvalue(L, 2);        lua_pushvalue(L, 3);        lua_rawset(L, -4);    }    lua_settop(L, 3);    return 0;}

 

第三個bug,使用I64d這種過時的標籤,I64d應該是微軟很老很老很老的一個格式化字串標籤,而且完全不具備可移植性。應該改為%lld。

static int tostring_s64(lua_State *L){    char temp[64];    sprintf_s(temp, "%I64d", *(long long*)lua_topointer(L, 1));    lua_pushstring(L, temp);    return 1;}

 

第4個bug,var_base基類的解構函式沒有寫virtual

struct var_base{    //原來的解構函式沒有寫virtual    virtual ~var_base() {};    virtual void get(lua_State *L) = 0;    virtual void set(lua_State *L) = 0;};

 

第5個bug,table的3個建構函式中有一個沒有增加引用計數,這個bug在網上很多同學都指出過。

lua_tinker::table::table(lua_State* L, const char* name){    lua_pushstring(L, name);    lua_gettable(L, LUA_GLOBALSINDEX);    if(lua_istable(L, -1) == 0)    {        lua_pop(L, 1);        lua_newtable(L);        lua_pushstring(L, name);        lua_pushvalue(L, -2);        lua_settable(L, LUA_GLOBALSINDEX);    }    m_obj = new table_obj(L, lua_gettop(L));        //原來的代碼沒有這段,缺少增加引用計數處理        m_obj->inc_ref();}

, CSDN的ainn_pp也寫過這個問題,參考:http://blog.csdn.net/ainn_pp/article/details/2773855

  1. 缺陷

LuaTinker也有很多缺陷和不足,

第一個不足,各種函數參數的支援個數參差不齊。LuaTinker的寫的時間應該比較早,沒有C++ 11的模版變參(Variadic Template)的支援,所以只能用寫多個模版函數(類)的方式解決多模板參數問題。但LuaTinker一方面寫的參數個數很少,一方面LuaTinker的個個地方支援的參數個數數量完全不統一,3個,4個,5個的都有。其實這部分最好用C++ 11的(Variadic Template)重寫。

第二個缺陷是個硬傷,LuaTinker對Lua 協程的支援,用了一個很費力,但又不討好的方式。你必須把協程的第一個參數定義為lua_State *L,而且返回值必須是lua_yield(L, 0)。這樣的限制,大大限制了使用。

//第一個參數必須是(lua_State *Lint TestFunc2(lua_State *L, float a){printf("# TestFunc2(L,%f) is invoke.\n", a);//返回的地方必須是調用lua_yield    return lua_yield(L, 0);}class TestClass{public:    //類函數也一樣    int TestFunc2(lua_State *L, float a)    {        printf("# TestClass::TestFunc2(L,%f) is invoke.\n", a);        return lua_yield(L, 0);    }};

 

而如果其實在其函數的封裝上加以區分,自己在最後調用lua_yield,這就可以避免這個麻煩。這個實現實在讓我沒有多大胃口。

第三個地方是,是對引用變數(參數),註冊的問題,其實這個也不是LuaTinker的問題,而是C++模版的問題,C++的自動模版函數參數推導是存在一些潛規則的。其中有一個就是左值變換,在《CUJ:高效使用標準庫:顯式函數模板參數申明與STL》 一文中有比較清晰的解釋。如下樣本:

//下面的寫法是無法得到引用的,必須顯式指定參數。//lua_tinker::set(L, "ref_a", ref_a);//顯式聲明引用參數lua_tinker::set<TestA &>(L, "ref_a", ref_a);

 

第4個問題就是,模版處理中,對於cv(const volatile)的去除掉處理也並不理想。Lua內部對於外部的class的註冊是使用函數class_add,也就是用一個名稱關聯一個Lua的meta table,在類的後面的使用中,通過class_name<T>::name函數取得類名,但實際中,很多時候T是帶有const 或者 volatile的修飾符的。包括,LuaTinker在部分處理中去掉了const,但很多地方又忽略問題,編譯器不會認為classA和const class A是一個東東的。所以結果就是有時候無法讓你的userdata找到對應的meta table。

lua_tinker::class_add<TestA>(L, "TestA");lua_tinker::class_con<TestA>(L, lua_tinker::constructor<TestA>);//用模板函數輔助幫忙實現一個方法,可以通過class 找到對應的類名稱(註冊到LUA的名稱),template<typename T>struct class_name{    // global name    static const char *name(const char *name = NULL)    {        static char temp[256] = "";        if (name)        {            strcpy_s(temp, name);        }        return temp;    }};

 

fergzhang同學,針對LuaTinker的一些bug修正做了一個版本。同時好像支援了5.2的版本,他放在了https://github.com/zfengzhen/lua_tinker_5.2.git

而我自己針對上面的問題實現了一套LuaTie的庫,沒有時間,有時間整理出來。內部用C++ 11的特性做了一些改寫。

https://github.com/sailzeng/zcelib/blob/master/src/commlib/zcelib/zce_script_lua_tie.cpp

https://github.com/sailzeng/zcelib/blob/master/src/commlib/zcelib/zce_script_lua_tie.h

工程內部是有測試的例子的,但沒有整理出來,看起來比較麻煩。等後面整理出來再寫一篇介紹的文章把。

最後,雖然我在挑刺,但還是再次表達一下對 LuaTinker作者Kwon-il Lee的感謝,這套代碼協助我瞭解了如何綁定指令碼以及瞭解MPL的一些基本知識.而且坦白講LuaBind是和Boost綁定的,能費力從這些代碼中簡化出LuaTinker(閱讀Boost代碼實在談不上愉快),真的是一件很了不起的事情,LuaTinker的作者可能更明白輕對於代碼的好處,Kwon-il Lee在首頁上有一段說明其為什麼沒有支援LuaBind所支援的重載,而我也認為一個優秀的庫始終要是簡單的。

LuaTinker的bug和缺陷

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.