1. 棧
1.1 說明
lua與C語言操作都是通過棧來進行的。這個棧是抽象的棧,棧中每一個元素都能保存任何類型的LUA值。
要獲得一個lua中的一個值時(例如一個全局變量),只要調用一個Lua的Api函數,Lua就會將指定的值壓入棧中。
要將一個值傳入Lua時,需要先將這個值壓入棧,然后再調用Lua Api,Lua就會獲取值並將此值從棧中彈出。
幾乎所有的lua api都會使用到棧,luaL_loadbuffer將它的結果(編譯好的程序或錯誤消息)留在棧中;lua_pcall會調用棧中的一個函數,若發生錯誤則將錯誤信息留在棧中。
1.2 棧的索引與查詢元素
以棧底為參考物:api使用“索引”來引用棧中的元素。第一個壓入棧中的元素索引為1;第二個壓入的元素索引為2依此類推。
以棧頂為參考物:使用負數的索引來訪問棧中的元素。此時,-1表示棧頂元素(最后一個壓入的元素),-2表示棧頂下面的一個,依此類推。
代碼測試
int _tmain(int argc, _TCHAR* argv[]) { lua_State *L = luaL_newstate(); luaL_openlibs(L); lua_pushstring(L,"this is a"); lua_pushstring(L,"this is b"); lua_pushstring(L,"this is c"); cout<<lua_tostring(L,1)<<endl; cout<<lua_tostring(L,2)<<endl; cout<<lua_tostring(L,3)<<endl; cout<<"---------------"<<endl; cout<<lua_tostring(L,-1)<<endl; cout<<lua_tostring(L,-2)<<endl; cout<<lua_tostring(L,-3)<<endl; lua_close(L); system("pause"); return 0; }
以上代碼的輸出結果為:
this is a
this is b
this is c
---------------
this is c
this is b
this is a
請按任意鍵繼續. . .
為了檢查一個元素是否為特定類型,API提供了類似lua_is*的函數,例如lua_isnumber等。實際上lua_isnumber不會檢查值是否為數字類別,而是檢查能否轉換為數字類型
lua_tolstring返回的字符串在其末尾會有一個額外的零,不過這些字符串中間也可能有零,字條串長度通過第三個參數len返回,這才是真正的字符串長度。盡管下總為真
size_t l; const char* s = lua_tolstring(L,-1,&l); assert(s[l] == '\0'); assert(strlen(s) <= 1)
因此遍歷棧有以下方法
//遍歷棧 static void statckDump(lua_State * L) { int nTop = lua_gettop(L); for(int i = 1;i <= nTop;i++ ) { int t = lua_type(L,i); switch(t) { case LUA_TSTRING: printf(" '%s' ",lua_tostring(L,i)); break; case LUA_TBOOLEAN: printf(lua_toboolean(L,i) ? "true" : "false"); case LUA_TNUMBER: printf("%g",lua_tonumber(L,i)); break; default: printf("%s",lua_typename(L,t)); break; } printf(" "); } printf("\n"); }
1.2 其它棧操作
int lua_gettop(lua_State * L)
返回棧中元素的個數,也可以說是棧頂元素的索引。int lua_settop(lua_State * L ,int index)
將棧頂設置為一個指定的位置,即修改元素數量。如果之前的棧比新設置的要高,那么高出來的那些會被丟棄。反之,會向棧中壓入nil來補足大小。有一個特例,調用lua_settop(L,0)能清空棧。也可以用負數索引來使用lua_settop。另外,API根據這個函數還提供了一個宏,用於從棧中彈出n個元素。
#define lua_pop(L,n) lua_settop(L,-(n)-1)lua_pushvalue函數會將指定索引上的值 的副本壓入棧。lua_remove刪除指定索引上的元素,並將該位置之上的所有元素下移以填補空缺。
lua_insert 會上移指定位置之上的所有元素以開辟一個槽的空間。然后將棧頂元素移動到該位置。
lua_replace彈出棧頂的值,並將該值 設置到指定索引上。但它不會移動任何東西。
int _tmain(int argc, _TCHAR* argv[]) { lua_State * L = luaL_newstate(); lua_pushboolean(L,1); lua_pushnumber(L,10); lua_pushnil(L); lua_pushstring(L,"hello"); statckDump(L); lua_pushvalue(L,-4);//將指定索引值壓入副本 statckDump(L); lua_replace(L,3); //彈出棧頂值 並把索引為3的元素替換 statckDump(L); lua_settop(L,6); //增高棧頂 statckDump(L); lua_remove(L,-3); //移除索引為-3 statckDump(L); lua_settop(L,-5); statckDump(L); lua_close(L); system("pause"); return 0; }
輸出結果為:
true 10 nil 'hello'
true 10 nil 'hello' true
true 10 true 'hello'
true 10 true 'hello' nil nil
true 10 true nil nil
true
請按任意鍵繼續. . .
最后說一下lua_pop
lua_pop(lua_State * L,int number);
此函數是從棧中彈出 number個元素,而不是彈出第number的元素