Lua學習與交流——Lua的棧(轉載)

【本文內容轉載自:http://blog.csdn.net/zxs421819166/article/details/6061253

1. 理解lua的棧到底是什麼?

    lua的棧類似於以下的定義, 它是在創建lua_State的時候創建的:

             TValue stack[max_stack_len]  // 欲知內情可以查 lstate.c 的stack_init函數

    存入棧的數據類型包括數值, 字符串, 指針, talbe, 閉包等, 下面是一個棧的例子:

          lua棧

   執行下面的代碼就可以讓你的lua棧上呈現圖中的情況

    lua_pushcclosure(L, func, 0) // 創建並壓入一個閉包

    lua_createtable(L, 0, 0)        // 新建並壓入一個表

    lua_pushnumber(L, 343)      // 壓入一個數字

    lua_pushstring(L, “mystr”)   // 壓入一個字符串

 

    這裏要說明的是, 你壓入的類型有數值, 字符串, 表和閉包[在c中看來是不同類型的值], 但是最後都是統一用TValue這種數據結構來保存的:), 下面用圖簡單的說明一下這種數據結構:

    lua

 

    TValue結構對應於lua中的所有數據類型, 是一個{值, 類型} 結構, 這就lua中動態類型的實現, 它把值和類型綁在一起, 用tt記錄value的類型, value是一個聯合結構, 由Value定義, 可以看到這個聯合有四個域, 先說明簡單的

        p -- 可以存一個指針, 實際上是lua中的light userdata結構

        n -- 所有的數值存在這裏, 不過是int , 還是float

        b -- Boolean值存在這裏, 注意, lua_pushinteger不是存在這裏, 而是存在n中, b只存布爾

        gc -- 其他諸如table, thread, closure, string需要內存管理垃圾回收的類型都存在這裏

        gc是一個指針, 它可以指向的類型由聯合體GCObject定義, 從圖中可以看出, 有string, userdata, closure, table, proto, upvalue, thread

    從下面的圖可以的得出如下結論:

        1. lua中, number, boolean, nil, light userdata四種類型的值是直接存在棧上元素裏的, 和垃圾回收無關.

        2. lua中, string, table, closure, userdata, thread存在棧上元素裏的只是指針, 他們都會在生命週期結束後被垃圾回收.

 

 

2. lua和c通信的約定

    lua和c通信時有這樣的約定: 所有的lua中的值由lua來管理, c++中產生的值lua不知道, 類似表達了這樣一種意思: "如果你(c/c++)想要什麼, 你告訴我(lua), 我來產生, 然後放到棧上, 你只能通過api來操作這個值, 我只管我的世界", 這個很重要, 因爲:

         "如果你想要什麼, 你告訴我, 我來產生"就可以保證, 凡是lua中的變量, lua要負責這些變量的生命週期和垃圾回收, 所以, 必須由lua來創建這些值(在創建時就加入了生命週期管理要用到的簿記信息)

         "然後放到棧上, 你只能通過api來操作這個值", lua api給c提供了一套完備的操作界面, 這個就相當於約定的通信協議, 如果lua客戶使用這個操作界面, 那麼lua本身不會出現任何"意料之外"的錯誤.

         "我只管我的世界"這句話體現了lua和c/c++作爲兩個不同系統的分界, c/c++中的值, lua是不知道的, lua只負責它的世界

 

 

3. lua value 和 c value的對應關係

             c          lua
         nil           無    {value=0, tt = t_nil}
      boolean       int  非0, 0    {value=非0/0, tt = t_boolean}
      number       int/float等   1.5    {value=1.5, tt = t_number}
   lightuserdata    void*, int*, 各種*  point    {value=point, tt = t_lightuserdata}
      string          char  str[]    {value=gco, tt = t_string}   gco=TString obj
      table            無    {value=gco, tt = t_table}  gco=Table obj
      userdata            無    {value=gco, tt = t_udata} gco=Udata obj
      closure            無    {value=gco, tt = t_function} gco=Closure obj

 

可以看出來, lua中提供的一些類型和c中是對應的, 也提供一些c中沒有的類型. 其中有一些藥特別的說明一下:

        nil值, c中沒有對應, 但是可以通過lua_pushnil向lua中壓入一個nil值

        注意: lua_push*族函數都有"創建一個類型的值並壓入"的語義, 因爲lua中所有的變量都是lua中創建並保存的, 對於那些和c中有對應關係的lua類型, lua會通過api傳來的附加參數, 創建出對應類型的lua變量放在棧頂, 對於c中沒有對應類型的lua類型, lua直接創建出對應變量放在棧頂.

       例如:    lua_pushstring(L, “string”) lua根據"string"創建一個 TString obj, 綁定到新分配的棧頂元素上

                  lua_pushcclosure(L,func, 0) lua根據func創建一個 Closure obj, 綁定到新分配的棧頂元素上

                  lua_pushnumber(L,5) lua直接修改新分配的棧頂元素, 將5賦值到對應的域

                  lua_createtable(L,0, 0)lua創建一個Tabke obj, 綁定到新分配的棧頂元素上

 

       總之, 這是一個 c value –> lua value的流向, 不管是想把一個簡單的5放入lua的世界, 還是創建一個table, 都會導致

                  1. 棧頂新分配元素    2. 綁定或賦值

                還是爲了重複一句話, 一個c value入棧就是進入了lua的世界, lua會生成一個對應的結構並管理起來, 從此就不再依賴這個c value

        lua value –> c value時, 是通過 lua_to* 族api實現, 很簡單, 取出對應的c中的域的值就行了, 只能轉化那些c中有對應值的lua value, 比如table就不能to c value, 所以api中夜沒有提供 lua_totable這樣的接口.


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章