C++與Lua交互的C API

1、C API的介紹

Lua是一種嵌入式的語言。即Lua不是一個單獨運行的程序,而是一個可以鏈接到其他程序的庫。通過C API就可以將Lua的功能合併入這些程序。與此同時,一個使用了Lua的程序可以在Lua環境中註冊用C語言實現的新函數,由此,就可以向Lua中添加某些無法直接用Lua編寫的功能。

由於Lua和C++的數據結構和內存機制不一樣,所以在交互的時候需要用到C API提供的一個虛擬棧,所有的操作其實全是對這個虛擬棧的操作,這個堆棧是先進後出的,棧底的索引爲1,依次向上加。也可以用負數來表示,棧頂的索引爲-1,依次往下減。所有的數據交換,無論是Lua到C語言或C語言到Lua都通過這個棧來完成,這個棧還可以保存中間結果。

C API是一組能使C代碼和Lua交互的函數。其中包括讀寫Lua全局變量,調用Lua函數,運行一段Lua代碼,以及註冊C函數以供Lua調用。裏面提供了一些頭文件,如lua.h lauxlib.h lualib.h等。

lua.h定義了Lua提供的基礎函數,包括創建lua環境,調用lua函數,讀寫lua中的全局變量,以及註冊供Lua調用的新函數等。這裏面的函數前綴都是lua_。

lauxlib.h是一個輔助庫,定義了輔助庫的輔助函數,這裏面的函數都是以luaL_開頭的。輔助庫是一個使用lua.h中API編寫出的一個較高的抽象層。lua的所有標準庫編寫都用到了輔助庫,輔助庫主要用來解決實際問題。

lualib.h定義了打開標準庫的函數。由於luaL_newstate函數用於創建一個新環境。這個新創建的環境中沒有包含預定義的函數,甚至沒有print。爲了使lua保持小巧,所有的標準庫都被組織到了不同的包中。在頭文件lualib.h中定義了打開這些庫的函數,而輔助庫函數luaL_openlibs則可以打開所有的標準庫。


2、lua.h函數介紹

這裏面有大量的push函數用於將C數據壓入虛擬棧中,如下:

void lua_pushnil (lua_State *L);
void lua_pushboolean (lua_State *L, int bool);
void lua_pushnumber (lua_State *L, double n);
void lua_pushlstring (lua_State *L, const char *s,
                                          size_t length);
void lua_pushstring (lua_State *L, const char *s);
lua中的字符串不是以0結尾的,因此它們必須包含一個顯式的長度。將字符串壓入棧的基本函數是lua_pushlstring,它要求傳入一個顯式的長度參數,對於0結尾的字符串,可以使用函數lua_pushstring,這個函數可以通過strlen來計算字符串的長度。另外,Lua不會持有指向外部字符串的指針。對於所有Lua持有的字符串,它都會生成一個內部副本,或者複用現有的內容。

另外在向棧中壓入一個元素時,應該確保棧中具有足夠的空間。當Lua啓動時,或者Lua調用C語言時,棧中至少會有20個空閒的位置。如果想要查看棧中是否有足夠的空間,可以調用:

int lua_checkstack (lua_State *L, int sz);

前面我們說過,這個棧是根據索引來查找元素的。第一個壓入棧的索引爲1,第二個爲2,一直到棧頂。負數的話,-1代表棧頂,-2代表棧頂下面的元素,一直到棧底。爲了檢查一個元素是否爲特定的類型,API提供了一系列的函數lua_is*,這裏的*可以是任意Lua類型。例如:lua_isnumber、lua_isstring、lus_istable等。類似這樣的函數的原型爲:

int lua_is... (lua_State *L, int index);

實際上,lua_isnumber並不會去檢查值是否爲數字類型和,而是檢查值是否能轉換爲數字類型。還有一個函數lua_type,它會返回棧中數據的類型。每種類型都有一個常亮表示,這些常量也都定義在lua.h中:

LUA_TNIL、LUA_TBOOLEAN、LUA_TNUMBER、LUA_TSTRING、LUA_TTABLE、LUA_TFUNCTION、LUA_TUSERDATA以及LUA_TTHREAD

從棧中取值的話一般是用lua_to*類似的函數:

int           lua_toboolean (lua_State *L, int index);
double        lua_tonumber (lua_State *L, int index);
const char *  lua_tostring (lua_State *L, int index);
size_t        lua_strlen (lua_State *L, int index);

如果說,咱們指定的元素轉換失敗的話,這些函數不會拋出錯誤,而是lua_toboolean、lua_tonumber、lua_tointeger和lua_objlen會返回0,其他一律返回NULL。另外要注意,lua_tolstring函數會返回一個指向內部字符串副本的指針,並將字符串的長度存入最後一個參數len中。lua_objlen這個函數可以返回一個對象的“長度”。對於字符串和table,這個值是長度操作符“#”的結果。

其他的一些函數也做一下總結:

int  lua_gettop (lua_State *L);
void lua_settop (lua_State *L, int index);
void lua_pushvalue (lua_State *L, int index);
void lua_remove (lua_State *L, int index);
void lua_insert (lua_State *L, int index);
void lua_replace (lua_State *L, int index);

lua_gettop返回棧中元素的個數,其實也就是返回棧頂的索引。lua_settop將棧頂設置爲一個指定的位置,也就是修改棧頂元素的數量,還是老套路,新的數量大於以前的,多出來的爲nil,新的數量少於以前的,那些就被拋棄了。


發佈了137 篇原創文章 · 獲贊 36 · 訪問量 38萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章