lua可作為擴充套件性語言(lua可以作為程式庫用來擴充套件應用的功能),同時也是個可擴充套件的語言(lua程式中可以註冊由其他語言實現的函式)。
c和lua互動的部分稱為c api。c api是乙個c**與lua進行互動的函式集。他由以下部分組成:
讀寫lua全域性變數的函式、
呼叫lua函式的函式、
執行lua**片斷的函式、
註冊c函式然後可以在lua中被呼叫的函式,等等。
api中有些函式為了方便以巨集的方式實現。
當在lua和c之間交換資料時我們面臨著兩個問題:動態與靜態型別系統的不匹配和自動與手動記憶體管理的不一致。解決辦法是在c和lua之間通訊關鍵在於乙個虛擬的棧。幾乎所有的api呼叫都是對棧上的值進行操作,所有c與lua之間的資料交換也都通過這個棧來完成。因為棧是由lua來管理的,垃圾**器知道那個值正在被c使用。
lua以乙個嚴格的lifo規則(後進先出;也就是說,始終訪問棧頂)來操作棧:
(1)當你呼叫lua時,它只會改變棧頂部分。
(2)你的c**卻有更多的自由;更明確的來講,你可以查詢棧上的任何元素,甚至是在任何乙個位置插入和刪除元素。
在呼叫c api時有幾個重要的標頭檔案:
(1)lua.h:lua基礎函式庫,lua_字首
(2)lauxlib.h:輔助庫,lual_字首,利用lua.h實現的更高層的抽象
(3)lualib.h:為了保持lua的苗條,所有的標準庫以單獨的包提供,所以如果你不需要就不會強求你使用它們。標頭檔案lualib.h定義了開啟這些庫的函式。例如,呼叫luaopen_io,以建立io table並註冊i/o函式(io.read,io.write等等)到lua環境中。
api用索引來訪問棧中的元素。棧底為1,依次往上增加,也可用負數索引,-1表示棧頂元素。下面列出一些常用的c api函式:
lua_push*:壓入棧元素
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_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);
lua_tostring函式返回乙個指向字串的內部拷貝的指標。你不能修改它(使你想起那裡有乙個const)。只要這個指標對應的值還在棧內,lua會保證這個指標一直有效。當乙個c函式返回後,lua會清理他的棧,所以,有乙個原則:永遠不要將指向lua字串的指標儲存到訪問他們的外部函式中。
size_t lua_strlen (lua_state *l, int index):返回字串的實際長度。
int lua_checkstack(lua_state *l, int sz):檢查棧空間。預設有20個空閒的記錄,lua.h中的lua_minstack巨集定義了這個常量。
int lua_is... (lua_state *l, int index):檢查乙個元素能否被轉換成指定的型別。
int lua_type (lua_state *l, int idx):返回棧中元素的型別;
const char* lua_typename(lua_state *l, int tp):返回type對應的名字字串,第二個引數為lua_type返回的型別
void lual_checktype (lua_state *l, int arg, int t):返回引數arg是否是型別t,第三個引數為lua_type的取值。
在lua.h標頭檔案中,每種型別都被定義為乙個常量:lua_tnil、lua_tboolean、lua_tnumber、lua_tstring、lua_ttable、lua_tfunction、lua_tuserdata以及lua_tthread。
int lua_gettop (lua_state *l):返回棧中元素個數,它也是棧頂元素的索引。
void lua_settop (lua_state *l, int index):設定棧頂元素的索引,相當於設定棧的大小。如果開始的棧頂高於新的棧頂,頂部的值被丟棄。否則,為了得到指定的大小這個函式壓入相應個數的空值(nil)到棧上。lua_settop(l,0):清空堆疊。
#define lua_pop(l,n) lua_settop(l, -(n)-1):巨集定義,彈出n個元素。
void lua_pushvalue (lua_state *l, int index):壓入堆疊上指定索引的乙個摶貝到棧頂,等於拷貝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和c++簡單互動的**:
#include #includeextern"c
" int main (void
) }
lua_close(l);
return0;
}
上述**在vs2010中正常執行,lua使用5.1的版本,其中有幾點需要注意的:
(1)lua5.0之前初始化庫的用法如下:
luaopen_base(l); /*opens the basic library
*/luaopen_table(l);
/*opens the table library
*/luaopen_io(l);
/*opens the i/o library
*/luaopen_string(l);
/*opens the string lib.
*/luaopen_math(l);
/*opens the math lib.
*/
但5.0之後只需要一句話即可:
lual_openlibs(l);
(2)需要新增依賴庫:lua5.1.lib lua51.lib。
下面這個例子可以有助於加深對c和lua之間堆疊的理解:
//從棧底到棧頂依次遍歷整個堆疊
static
void stackdump(lua_state*l)
printf(""
); }
printf("\n
");}int main(void
)
注意lua_replace首先會彈出棧頂元素,並且需要注意的是lua_replace(l, -1);語句會導致站頂元素彈出,其他元素不變。
作為配置語言是lua的乙個重要應用,下面看乙個簡單的這方面的例子。有乙個含有簡單字段記錄的lua檔案如下:
width = 200height = 300
對該lua檔案的解析大媽如下:
#include #include #include #include extern "c" void
error(lua_state* l, const char*fmt, ...)
void
load(char* filename, int* width, int*height)
lua_getglobal(l,
"width");
lua_getglobal(l,
"height");
if(!lua_isnumber(l, -2
))
error(l, "
'width' should be a number\n");
if(!lua_isnumber(l, -1
))
error(l, "
'height' should be a number\n");
*width = (int)lua_tonumber(l, -2
); *height = (int)lua_tonumber(l, -1
); lua_close(l);
}int main(void)
Lua和C語言的互動(一)
lua生來就是為了和c互動的,因此使用c擴充套件lua或者將lua嵌入到c當中都是非常流行的做法。要想理解c和lua的互動方式,首先要回顧一下c語言是如何處理函式引數的。c函式和引數 大家知道c語言是用彙編實現的,在組合語言中可沒有函式的概念,與函式對應的是叫做子過程的東西,子過程就是一段指令,乙個...
Lua和C語言的互動(一)
lua生來就是為了和c互動的,因此使用c擴充套件lua或者將lua嵌入到c當中都是非常流行的做法。要想理解c和lua的互動方式,首先要回顧一下c語言是如何處理函式引數的。c函式和引數 大家知道c語言是用彙編實現的,在組合語言中可沒有函式的概念,與函式對應的是叫做子過程的東西,子過程就是一段指令,乙個...
Lua和C 語言的互動詳解
前言 寫過windows程式的人都知道,對於應用程式,如果需要在本地儲存一些配置資訊,我們經常將這些配置資訊寫在登錄檔或者本地的配置檔案中,很多應用都是將一些配置資訊寫在配置檔案中,比如以ini結尾的檔案,這種配置檔案很多,使用的很廣泛,然後應用程式在啟動的時候,就會解析這個配置檔案,讀取一些配置資...