生活随笔
收集整理的這篇文章主要介紹了
Lua 和 C 交互中虚拟栈的操作和遍历
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
int lua_pcall(lua_State *L, int nargs, int nresults, int msgh)
?* 以保護(hù)模式調(diào)用具有"nargs"個(gè)參數(shù),"nresults"個(gè)返回值得函數(shù)。函數(shù)在第一個(gè)參數(shù)的前一個(gè)位置。
?* 保護(hù)模式指的是當(dāng)調(diào)用出錯(cuò)時(shí)不會報(bào)錯(cuò),而是返回一個(gè)錯(cuò)誤碼同時(shí)將錯(cuò)誤信息入棧。
?* 當(dāng)調(diào)用成功時(shí),函數(shù)返回0。將函數(shù)名以及參數(shù)出棧,之后將函數(shù)的返回值入棧。
?* 無論函數(shù)返回多少個(gè)返回值,Lua會調(diào)整為你需要的數(shù)量,忽略多余的或者將不夠的補(bǔ)為"nil"。
?* 當(dāng)調(diào)用出錯(cuò)時(shí),函數(shù)返回非0值。將函數(shù)名以及參數(shù)出棧,
?* 以錯(cuò)誤信息作為參數(shù),執(zhí)行虛擬棧中索引"msgh"處的出錯(cuò)處理函數(shù),
?* 將出錯(cuò)處理函數(shù)的返回值作為"lua_pcall"的返回值入棧。
?* "msgh"為0代表沒有錯(cuò)誤處理函數(shù),錯(cuò)誤處理函數(shù)必須要在被調(diào)用函數(shù)和其參數(shù)入棧之前入棧。
?* 典型的用法中,錯(cuò)誤處理函數(shù)被用來給錯(cuò)誤消息加上更多的調(diào)試信息,比如棧跟蹤信息。
?* 這些信息在"lua_pcall"返回后,由于棧已經(jīng)展開,所以收集不到了。
?* lua_pcall 函數(shù)會返回下列常數(shù)(定義在"lua.h"內(nèi))中的一個(gè):
? ?LUA_OK (0): 成功。
? ?LUA_ERRRUN: 運(yùn)行時(shí)錯(cuò)誤(一般錯(cuò)誤)。
? ?LUA_ERRMEM: 內(nèi)存分配錯(cuò)誤(此種情況,Lua不會調(diào)用錯(cuò)誤處理函數(shù))。
? ?LUA_ERRERR: 在運(yùn)行錯(cuò)誤處理函數(shù)時(shí)發(fā)生的錯(cuò)誤(此種情況,Lua不會再次調(diào)用錯(cuò)誤處理函數(shù))。
? ?LUA_ERRGCMM: 在運(yùn)行"__gc"元方法時(shí)發(fā)生的錯(cuò)誤(這個(gè)錯(cuò)誤和被調(diào)用的函數(shù)無關(guān)。)。
?
#include <iostream>
#include <lua.hpp>/* // lua.hpp 中的內(nèi)容
// lua 是以ANSI C編寫的, 所以在C++中使用必須加上 extern "C" { } , 顯示的告訴編譯器以C的方式編譯代碼
extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}
*//** Lua中的字符串可以不以'\0'作為結(jié)束符。這樣,字符串中可以包含任意的二進(jìn)制(甚至是'\0'),字符串的長度由明確的長度指定* 在lua_pushlstring()、lua_pushliteral()以及l(fā)ua_pushstring()中,Lua不保存字符串(變量)指針。因此當(dāng)這些函數(shù)返回時(shí),你就可以修改你的字符串了* 遍歷一個(gè)”table”時(shí),不要將lua_tolstring()作用在”key”上,這樣會導(dǎo)致lua_next()無法正常運(yùn)行** 對于入棧是否有棧空間的情況,你需要自己判斷,別忘了現(xiàn)在你是一個(gè)C程序員。當(dāng)Lua啟動或者任何Lua調(diào)用C的時(shí)候,虛擬棧中至少有20個(gè)空間(在”lua.h”中LUA_MINSTACK定義),這對于一般情況下夠用了,所以一般不用考慮。但有時(shí)候確實(shí)需要更多的棧空間(比如調(diào)用一個(gè)不定參數(shù)的函數(shù)),此時(shí)你需要使用lua_checkstack檢查棧空間的情況** int lua_checkstack(lua_State *L, int sz)* 確保堆棧上至少有"n"個(gè)額外空位。如果不能把堆棧擴(kuò)展到相應(yīng)的尺寸,函數(shù)返回"false"。* 失敗的原因包括將把棧擴(kuò)展到比固定最大尺寸還大(至少是幾千個(gè)元素)或分配內(nèi)存失敗。* 這個(gè)函數(shù)永遠(yuǎn)不會縮小堆棧,如果堆棧已經(jīng)比需要的大了,那么就保持原樣。** 在平常的編碼中,對于執(zhí)行失敗時(shí)會返回0的lua_to*()類別的函數(shù),我們最好先使用lua_is*()類別的函數(shù)判斷參數(shù)的類型,之后再使用lua_to*()類別的函數(shù)對參數(shù)進(jìn)行轉(zhuǎn)換;而對于執(zhí)行失敗時(shí)會返回NULL的lua_to*()類別的函數(shù),我們可以直接使用lua_to*()類別的函數(shù)直接對參數(shù)進(jìn)行轉(zhuǎn)換,判斷函數(shù)的返回值非NULL與否,就能判斷轉(zhuǎn)換是否成功** lua_pop()就是通過lua_settop()實(shí)現(xiàn)的(在”lua.h”中定義)* #define lua_pop(L,n) lua_settop(L, -(n)-1)** 以下操作對于虛擬棧沒有任何影響, 棧中元素個(gè)數(shù)還是一樣多* lua_settop(L, -1); // set top to its current value* lua_insert(L, -1); // move top element to the top* lua_replace(L, -1); // replace top element by the top element**/static void stackDump(lua_State * L)
{int i = 0;int top = lua_gettop(L); // 獲取棧中元素個(gè)數(shù)std::cout << "lua stack value count: " << top << std::endl;for (i = 1; i <= top; ++i) // 遍歷棧中每一個(gè)元素 // 棧底的序號為1, 依次遞增. 棧頂?shù)男蛱柺冀K為-1{int t = lua_type(L, i); // 獲取元素的類型switch (t){case LUA_TSTRING: // stringsstd::cout << lua_tostring(L, i);break;case LUA_TBOOLEAN: // boolstd::cout << (lua_toboolean(L, i) != 0 ? "true" : "false");break;case LUA_TNUMBER: // numberstd::cout << lua_tonumber(L, i);break;default: // other valuesstd::cout << lua_typename(L, t); // 將宏定義的類型碼轉(zhuǎn)換為類型名稱break;}std::cout << " ";}std::cout << std::endl;
}int main()
{lua_State * L = luaL_newstate(); // 創(chuàng)建Lua虛擬機(jī)luaL_openlibs(L); // 打開Lua狀態(tài)機(jī)"L"中的所有Lua標(biāo)準(zhǔn)庫// 向虛擬棧中壓入值lua_pushboolean(L, 1); // truelua_pushnumber(L, 10); // 10lua_pushnil(L); // nillua_pushstring(L, "hello"); // "hello"stackDump(L); // true 10 nil 'hello'lua_pushvalue(L, -4); // 將索引-4處的值的副本入棧stackDump(L); // true 10 nil 'hello' truelua_replace(L, 3); // 將棧頂元素移動到索引3處,并覆蓋原先的元素stackDump(L); // true 10 true 'hello'lua_settop(L, 6); // 將棧頂設(shè)置為索引6處,多出來的新元素被賦值為"nil"stackDump(L); // true 10 true 'hello' nil nillua_remove(L, -3); // 移除索引-3處的元素,其上所有元素下移stackDump(L); // true 10 true nil nillua_settop(L, -5); // 將棧頂設(shè)置為索引-5處stackDump(L); // truelua_close(L); // 關(guān)閉Lua狀態(tài)機(jī)std::cout << "..." << std::endl;system("pause");return 0;
}
?
總結(jié)
以上是生活随笔為你收集整理的Lua 和 C 交互中虚拟栈的操作和遍历的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。