C/C++和Lua是如何進行通訊的?

爲了實現Lua和其餘語言之間的通訊,Lua虛擬機爲C/C++提供了兩個特性:
html

一,Lua_State狀態機數組

       lua_State主要是管理一個lua虛擬機的執行環境, 一個lua虛擬機能夠有多個執行環境。Lua虛擬機經過維護這樣一個虛擬棧來實現兩種之間的通訊,lua_State定義以下:數據結構

struct lua_State {
  CommonHeader;
  lu_byte status;
  StkId top;  /* first free slot in the stack */
  global_State *l_G;
  CallInfo *ci;  /* call info for current function */
  const Instruction *oldpc;  /* last pc traced */
  StkId stack_last;  /* last free slot in the stack */
  StkId stack;  /* stack base */
  int stacksize;
  unsigned short nny;  /* number of non-yieldable calls in stack */
  unsigned short nCcalls;  /* number of nested C calls */
  lu_byte hookmask;
  lu_byte allowhook;
  int basehookcount;
  int hookcount;
  lua_Hook hook;
  GCObject *openupval;  /* list of open upvalues in this stack */
  GCObject *gclist;
  struct lua_longjmp *errorJmp;  /* current error recover point */
  ptrdiff_t errfunc;  /* current error handling function (stack index) */
  CallInfo base_ci;  /* CallInfo for first level (C calling Lua) */
};

        1,虛擬棧的管理, 包括管理整個棧和當前函數使用的棧的狀況函數

        2,CallInfo的管理, 包括管理整個CallInfo數組和當前函數的CallInfo網站

        3,hook相關的, 包括hookmask, hookcount, hook函數等this

        4,global_State是全局惟一的,存放多個lua_State之間的一些共享數據lua

        5,gc的一些管理和當前棧中upvalue的管理spa

        6,錯誤處理的支持等等指針

        C/C++和Lua擁有不一樣的數據類型,要實現二者之間的數據通訊怎麼辦?Lua虛擬機提供Lua_State這樣一種數據結構。任何一種數據從C/C++傳入Lua虛擬機中,Lua都會將這類數據轉換爲一種通用的結構lua_TValue,而且將數據複製一份,將其壓入虛擬棧中。lua_TValue定義以下:code

struct lua_TValue {
  TValuefields;
};

#define TValuefields  \
	union { struct { Value v__; int tt__; } i; double d__; } u

union Value {
  GCObject *gc;    /* collectable objects */
  void *p;         /* light userdata */
  int b;           /* booleans */
  lua_CFunction f; /* light C functions */
  numfield         /* numbers */
};

       Lua有本身的GC,C/C++由本身申請和釋放內存,因此二者之間的內存管理是獨立的。從C/C++中傳遞數據到Lua虛擬機會發生數據拷貝,從Lua虛擬機中傳遞出來是直接從虛擬棧中取值或者地址,因此數據從虛擬棧中pop以後,是否依然是有效引用須要額外注意。

 二,C API

Lua腳本實現交互提供了一系列的C API,經常使用API有:

        luaL_newstate函數用於初始化一個lua_State實例

        luaL_openlibs函數用於打開Lua中的全部標準庫,如io庫、string庫等。

        luaL_loadbuffer編譯了buff中的Lua代碼,若是沒有錯誤,則返回0,同時將編譯後的程序塊壓入虛擬棧中。

        lua_pcall函數會將程序塊從棧中彈出,並在保護模式下運行該程序塊。執行成功返回0,不然將錯誤信息壓入棧中。

        lua_tostring函數中的-1,表示棧頂的索引值,棧底的索引值爲1,以此類推。該函數將返回棧頂的錯誤信息,可是不會將其從棧中彈出。

        lua_pop是一個宏,用於從虛擬棧中彈出指定數量的元素,這裏的1表示僅彈出棧頂的元素。

        lua_close用於釋放狀態指針所引用的資源。

入棧操做:

        Lua針對每種C類型,都有一個C API函數與之對應,如:

        void lua_pushnil(lua_State* L);  --nil值

        void lua_pushboolean(lua_State* L, int b); --布爾值

        void lua_pushnumber(lua_State* L, lua_Number n); --浮點數

        void lua_pushinteger(lua_State* L, lua_Integer n);  --整型

        void lua_pushlstring(lua_State* L, const char* s, size_t len); --指定長度的內存數據

        void lua_pushstring(lua_State* L, const char* s);  --以零結尾的字符串,其長度可由strlen得出。 

出棧操做:

        API使用「索引」來引用棧中的元素,第一個壓入棧的爲1,第二個爲2,依此類推。咱們也可使用負數做爲索引值,其中-1表示爲棧頂元素,-2爲棧頂下面的元素,一樣依此類推。

        Lua提供了一組特定的函數用於檢查返回元素的類型,如:

        int lua_isboolean (lua_State *L, int index);

        int lua_iscfunction (lua_State *L, int index);

        int lua_isfunction (lua_State *L, int index);

        int lua_isnil (lua_State *L, int index);

        int lua_islightuserdata (lua_State *L, int index);

        int lua_isnumber (lua_State *L, int index);

        int lua_isstring (lua_State *L, int index);

        int lua_istable (lua_State *L, int index);

        int lua_isuserdata (lua_State *L, int index);

        以上函數,成功返回1,不然返回0。須要特別指出的是,對於lua_isnumber而言,不會檢查值是否爲數字類型,而是檢查值是否能轉換爲數字類型。

有關API的具體用法或者瞭解更多的API請訪問其官方網站

若有任何疑問和建議,歡迎指出討論,謝謝~

相關文章
相關標籤/搜索