lua中得棧


如果你看了LUA的文檔,那么就應該很清楚LUA與C交互數據時都是用到LUA中所謂的stack。那么當我調用lua_open函數之后棧是什么樣的呢?空的(luaopen_base等會往棧上加進一些東西)。那么至於如何操作棧上的數據,我想官方文檔上已經說得很清楚了,不過最初我對於棧的順序有一些迷糊,所以就說說這個。現在假如我有如下的一段代碼: 

代碼:
lua_State* L = lua_open();
lua_pushnumber( L, 211 );
lua_pushnumber( L, 2222 );
lua_newtable( L );
lua_close( L );



那么當執行完lua_newtable之后棧上有三個元素,大致就是這樣: 

211 
222 
table 

現在211是第一個元素,index為1,不過LUA也可以用負數來表示,那么現在他是多少? 

index -index value 
1 -3 211 
2 -2 222 
3 -1 table 

嗯,很簡單,再看看如果我們要設置一個TABLE的值怎么做?文檔中說用lua_settable或是lua_rawset(這兩者有什么區別應該和這里說的無關),它們參數意義、以及准備工作都一樣,-1是值,-2是鍵值 
lua_settable( lua_state*, int ) 
第一個參數是要操作的腳本環境,第二個則是要操作的表在棧上的位置 
一般的寫法可能是這樣 

代碼:
// 代碼A
lua_getglobal( L, "myTable" );   // 獲取要設置值的table
lua_pushstring( L, "hp" );         // "hp"在棧上的位置為-1
lua_pushnumber( L, 211 );          // "hp"在棧上的位置變為-2,而211則是-1
lua_settable( L, -3 );               // 值被正確的設置到全局變量(表)的myTable中


如果我是想把hp這個值設置到全局表中呢?一般通過調用lua_setglobal宏 

代碼:
lua_pushnumber( L, 211 );
lua_setglobal( L, "hp" );


就這么簡單,不過我們來看看lua_setglobal這個宏 

代碼:
#define lua_setglobal(L,s)    /
   (lua_pushstring(L, s), lua_insert(L, -2), lua_settable(L, LUA_GLOBALSINDEX))


這么看來實際上我們上面的代碼被替換成了 

代碼:
lua_pushnumber( L, 211 );
lua_pushstring( L, "hp" );
lua_insert( L, -2 );         // 這一步看上去或許比較詭異,實際上是把-1的值放到lua_insert的第二個參數所指的位置,然后這個位置后面的參數往上移
                               //這里實際上最終結果就是-1和-2對調,但從邏輯上並不是對調
lua_settable( L, LUA_GLOBALSINDEX );         // 這里為什么不用lua_rawset?我認為是有原因的^@^



將上面的代碼與代碼A結合起來看,在lua_settable時index值不同,而它做的工作是如果發現index是LUA_GLOBALSINDEX 那么就取出全局表(還有一個LUA_REGISTERINDEX,類似),否則從stack上取元素,當然,這個棧位置取出的不是一個table就會失敗。所以代碼A中指定的是-3是剛從全局表中取出的myTable表(這里假設他是一個table),上面的代碼片段則是取出的全局表。所以lua_settable的index是什么值都可以,只要它指向的是一個table 

實際上lua中與c的接口也就主要在棧的操作上,基本上你在寫一個lua與C結合的程序時你最最需要做的工作就是明白你當前棧上有什么元素以及它們的位置。我一般會在紙上畫出他們的位置,如果你熟了,對於幾句在一起有關聯的lua調用則可以很快的看出棧的變化。比如lua_gettable/lua_rawget 

代碼:
lua_pushstring( L, "hp" );
lua_gettable( L, LUA_GLOBALSINDEX );


只看第一句,棧頂是一個字符串,但兩句放在一起,最終棧頂是一個全局表上一個名為hp的實際值 

代碼:
lua_pushstring( L, "hp" );
lua_pushnumber( L, 211 );
lua_settable( L, LUA_GLOBALSINDEX );


無論第二句pushnumber還是pushvalue,pushstring什么的,最終這三句執行之后對於棧來說是沒有任何變化的,因為lua_settable/lua_rawset會移走-1和-2 

總之,對於棧的變化,在看一個函數的文檔時先看它參數又需要棧上那些位置的元素並正確設置棧上的值,看清楚他會取棧上那些位置的元素作為這個lua api調用的使用並為之把正確的值放到棧上,最后注意函數完成之后會清除/移走那些位置的元素,我想應該就沒什么問題了


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM