void lua_newtable (lua_State *L);
創(chuàng)建一個(gè)空 table ,并將之壓入堆棧。 它等價(jià)于 lua_createtable(L, 0, 0)
。
int lua_gettop (lua_State *L);
返回棧頂元素的索引。 因?yàn)樗饕菑?nbsp;1 開始編號(hào)的, 所以這個(gè)結(jié)果等于堆棧上的元素個(gè)數(shù)(因此返回 0 表示堆棧為空)。
luaL_newmetatable
int luaL_newmetatable (lua_State *L, const char *tname);
如果注冊(cè)表中已經(jīng)有Key為tname的數(shù)據(jù)則返回0. 否則創(chuàng)建一個(gè)新表作為userdata的metatable,并在注冊(cè)表中注冊(cè)它然后返回1. 不過(guò)兩種情況都會(huì)把注冊(cè)表中tname相關(guān)的值壓入堆棧。
void *luaL_checkudata (lua_State *L, int narg, const char *tname);
Checks whether the function argument narg
is a userdata of the type tname
(see luaL_newmetatable
).
void lua_pushstring (lua_State *L, const char *s);
把指針 s
指向的以零結(jié)尾的字符串壓棧。 Lua 對(duì)這個(gè)字符串做一次內(nèi)存拷貝(或是復(fù)用一個(gè)拷貝), 因此 s
處的內(nèi)存在函數(shù)返回后,可以釋放掉或是重用于其它用途。 字符串中不能包含有零字符;第一個(gè)碰到的零字符會(huì)認(rèn)為是字符串的結(jié)束。
void lua_pushlstring (lua_State *L, const char *s, size_t len);
把指針 s
指向的長(zhǎng)度為 len
的字符串壓棧。 Lua 對(duì)這個(gè)字符串做一次內(nèi)存拷貝(或是復(fù)用一個(gè)拷貝), 因此 s
處的內(nèi)存在函數(shù)返回后,可以釋放掉或是重用于其它用途。 字符串內(nèi)可以保存有零字符。
void lua_pushvalue (lua_State *L, int index);
把堆棧上給定有效處索引處的元素作一個(gè)拷貝壓棧。
void lua_settable (lua_State *L, int index);
作一個(gè)等價(jià)于 t[k] = v
的操作, 這里 t
是一個(gè)給定有效索引 index
處的值, v
指棧頂?shù)闹担?而 k
是棧頂之下的那個(gè)值。
這個(gè)函數(shù)會(huì)把鍵和值都從堆棧中彈出。 和在 Lua 中一樣,這個(gè)函數(shù)可能觸發(fā) "newindex" 事件的元方法 (參見 §2.8)。
void lua_pushcfunction (lua_State *L, lua_CFunction f);
將一個(gè) C 函數(shù)壓入堆棧。 這個(gè)函數(shù)接收一個(gè) C 函數(shù)指針,并將一個(gè)類型為 function
的 Lua 值 壓入堆棧。當(dāng)這個(gè)棧定的值被調(diào)用時(shí),將觸發(fā)對(duì)應(yīng)的 C 函數(shù)。
注冊(cè)到 Lua 中的任何函數(shù)都必須遵循正確的協(xié)議來(lái)接收參數(shù)和返回值 (參見 lua_CFunction
)。
lua_pushcfunction
是作為一個(gè)宏定義出現(xiàn)的:
#define lua_pushcfunction(L,f) lua_pushcclosure(L,f,0)
int lua_setmetatable (lua_State *L, int index);
把一個(gè) table 彈出堆棧,并將其設(shè)為給定索引處的值的 metatable 。
void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n);
把一個(gè)新的 C closure 壓入堆棧。
當(dāng)創(chuàng)建了一個(gè) C 函數(shù)后,你可以給它關(guān)聯(lián)一些值,這樣就是在創(chuàng)建一個(gè) C closure (參見 §3.4); 接下來(lái)無(wú)論函數(shù)何時(shí)被調(diào)用,這些值都可以被這個(gè)函數(shù)訪問(wèn)到。 為了將一些值關(guān)聯(lián)到一個(gè) C 函數(shù)上, 首先這些值需要先被壓入堆棧(如果有多個(gè)值,第一個(gè)先壓)。 接下來(lái)調(diào)用 lua_pushcclosure
來(lái)創(chuàng)建出 closure 并把這個(gè) C 函數(shù)壓到堆棧上。 參數(shù) n
告之函數(shù)有多少個(gè)值需要關(guān)聯(lián)到函數(shù)上。 lua_pushcclosure
也會(huì)把這些值從棧上彈出。
void *lua_newuserdata (lua_State *L, size_t size);
這個(gè)函數(shù)分配分配一塊指定大小的內(nèi)存塊, 把內(nèi)存塊地址作為一個(gè)完整的 userdata 壓入堆棧,并返回這個(gè)地址。
userdata 代表 Lua 中的 C 值。 完整的 userdata 代表一塊內(nèi)存。 它是一個(gè)對(duì)象(就像 table 那樣的對(duì)象): 你必須創(chuàng)建它,它有著自己的元表,而且它在被回收時(shí),可以被監(jiān)測(cè)到。 一個(gè)完整的 userdata 只和它自己相等(在等于的原生作用下)。
當(dāng) Lua 通過(guò) gc
元方法回收一個(gè)完整的 userdata 時(shí), Lua 調(diào)用這個(gè)元方法并把 userdata 標(biāo)記為已終止。 等到這個(gè) userdata 再次被收集的時(shí)候,Lua 會(huì)釋放掉相關(guān)的內(nèi)存。
lua_touserdata
void *lua_touserdata (lua_State *L, int index);
如果給定索引處的值是一個(gè)完整的 userdata ,函數(shù)返回內(nèi)存塊的地址。 如果值是一個(gè) light userdata ,那么就返回它表示的指針。 否則,返回 NULL 。
Lua調(diào)用C++類要點(diǎn):
1. 為此類建立一個(gè)全局表,表名為類名tbClass;
lua_newtable(L);
int methods = lua_gettop(L);
lua_pushstring(L, T::className);
lua_pushvalue(L, methods);
lua_settable(L, LUA_GLOBALSINDEX);
2.注冊(cè)一個(gè)key為T::className的metatable,并制定其中的一些成員,用于之后生成的userdata。
// 這個(gè)表用于userdata(T的對(duì)象)的metatable
luaL_newmetatable(L, T::className);
int metatable = lua_gettop(L);
// metatable["__index"] = tbClass
lua_pushliteral(L, "__index");
lua_pushvalue(L, methods);
lua_settable(L, metatable);
// metatable["__tostring"] = tostring_T
lua_pushliteral(L, "__tostring");
lua_pushcfunction(L, tostring_T);
lua_settable(L, metatable);
// metatable["__gc"] = gc_T
lua_pushliteral(L, "__gc");
lua_pushcfunction(L, gc_T);
lua_settable(L, metatable);
3. 為此表指定成員,每個(gè)成員的key為類的成員函數(shù)名,Value為一個(gè)帶有閉包的統(tǒng)一函數(shù)。比如tbClass[FunName] = thunk,之后可以根據(jù)閉包得到具體是調(diào)用到哪個(gè)函數(shù)。閉包中有函數(shù)名和相應(yīng)函數(shù)的組合結(jié)構(gòu)(以lightuserdata的形式賦給閉包)。這些類成員函數(shù)參數(shù)都必須包括lua_State,因?yàn)樗枰膮?shù)都會(huì)在lua堆棧中。
// 為tbClass填充成員函數(shù)
for (RegType *l = T::methods; l->name; l++)
{
/* edited by Snaily: shouldn't it be const RegType *l ... ? */
lua_pushstring(L, l->name);
// 把(函數(shù)名,函數(shù)地址)pair以lightuserdata的形式作為C closure的upvalue入棧
lua_pushlightuserdata(L, (void*)l);
// 把一個(gè)新的C closure 壓入堆棧。為upvalue的個(gè)數(shù),并指定回調(diào)函數(shù)統(tǒng)一為thunk lua_pushcclosure(L, thunk, 1);
// tbClass[FunName] = Function
lua_settable(L, methods);
}
4.創(chuàng)建C對(duì)象給腳本使用b = Account.new(Account, 30); new是tbClass下的一個(gè)函數(shù)(另外指定的,不會(huì)掉到thunk,這一句會(huì)調(diào)用到C的一個(gè)函數(shù),里面會(huì)生成一個(gè)C對(duì)象,然后創(chuàng)建一個(gè)userdata 用于關(guān)聯(lián)到這個(gè)新生成的C對(duì)象。最后為這個(gè)userdata綁定上我們上面注冊(cè)為T::classname的metatable。因?yàn)槎ㄖ屏薽etatable的__index成員,所以當(dāng)userdata找不到的成員會(huì)去調(diào)用__index,因?yàn)橹拔覀儼裚_index綁定到tbClass,所以也會(huì)調(diào)用到tbClass的相應(yīng)成員。
// 創(chuàng)建一個(gè)新的T對(duì)象,并創(chuàng)建一個(gè)基于userdataType的userdata,其中保護(hù)了指向T對(duì)象的指針
static int new_T(lua_State *L)
{
lua_remove(L, 1); // use classname:new(), instead of classname.new()
T *obj = new T(L); // call constructor for T objects
userdataType *ud =
static_cast<userdataType*>(lua_newuserdata(L, sizeof(userdataType)));
ud->pT = obj; // store pointer to object in userdata
luaL_getmetatable(L, T::className); // lookup metatable in Lua registry
lua_setmetatable(L, -2);
return 1; // userdata containing pointer to T object
}
5. 當(dāng)腳本中指定函數(shù)被調(diào)用的時(shí)候,比如b:deposit(50.30)的時(shí)候,b是userdata,它的metatable的__index和tbClass綁定(見4),所以會(huì)調(diào)用到tbClass的相應(yīng)成員,就是之前關(guān)聯(lián)的thunk:這個(gè)時(shí)候L的堆棧里面有這個(gè)函數(shù)的兩個(gè)參數(shù),一個(gè)是b本身,一個(gè)是50.30。b是userdata,可以根據(jù)它取出對(duì)象的指針。見第4步。另外函數(shù)被調(diào)用的時(shí)候,它相關(guān)的upvalue也可以取得到,見步驟3。有了對(duì)象指針和相應(yīng)的函數(shù),調(diào)用也不為難了,記住參數(shù)50.30是保存在堆棧中傳給類的成員函數(shù)來(lái)取得。
// 所有成員函數(shù)都會(huì)調(diào)用到這里,然后根據(jù)upvalue來(lái)執(zhí)行具體的成員函數(shù)
static int thunk(lua_State *L)
{
// stack has userdata, followed by method args
T *obj = check(L, 1); // the object pointer from the table at index 0.
lua_remove(L, 1); // remove self so member function args start at index 1
// get member function from upvalue
RegType *l = static_cast<RegType*>(lua_touserdata(L, lua_upvalueindex(1)));
return (obj->*(l->mfunc))(L); // call member function
}
// 根據(jù)指定位置narg獲得對(duì)象指針,這個(gè)userdata是在new_T的時(shí)候創(chuàng)建的
static T *check(lua_State *L, int narg)
{
void *pUserData = luaL_checkudata(L, narg, T::className);
userdataType *ud = static_cast<userdataType*>(pUserData); // 這個(gè)是函數(shù)的upvalue
if(!ud)
luaL_typerror(L, narg, T::className);
return ud->pT;
}