歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> C\C++和Lua是如何進行通信的?

C\C++和Lua是如何進行通信的?

日期:2017/3/1 9:39:40   编辑:Linux編程

為了實現Lua和其他語言之間的通信,Lua虛擬機為C\C++提供了兩個特性:

一,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函數等

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

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

6,錯誤處理的支持等等

C\C++和Lua擁有不同的數據類型,要實現兩者之間的數據通信怎麼辦?Lua虛擬機提供Lua_State這樣一種數據結構。任何一種數據從C\C++傳入Lua虛擬機中,Lua都會將這類數據轉換為一種通用的結構lua_TValue,並且將數據復制一份,將其壓入虛擬棧中。lua_TValue定義如下:

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請訪問其官方網站

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

Lua 語言 15 分鐘快速入門 http://www.linuxidc.com/Linux/2013-06/86582.htm

Lua程序設計(第2版)中文 PDF http://www.linuxidc.com/Linux/2013-03/81833.htm

Lua程序設計(第二版)閱讀筆記 http://www.linuxidc.com/Linux/2013-03/81834.htm

NetBSD 將支持用 Lua 腳本開發內核組件 http://www.linuxidc.com/Linux/2013-02/79527.htm

CentOS 編譯安裝 Lua LuaSocket http://www.linuxidc.com/Linux/2011-08/41105.htm

Lua 的詳細介紹:請點這裡
Lua 的下載地址:請點這裡

Copyright © Linux教程網 All Rights Reserved