Lua棧介紹以及實例

c++中載入lua的代碼

#include <> //所需要的頭文件
extern "C"
{
#include "include/lua.h"
#include "include/lualib.h"
#include "include/lauxlib.h"
#pragma comment(lib, "lua.lib")
};

int main(void)
{
        char buff[256]; //棧
        int error; //錯誤代碼

        lua_State* L = lua_open(); //lua指針
        luaL_openlibs(L); //載入所有lua庫

        //在此加入所需代碼...

        lua_close(L); //關閉lua

        return 0;
}

 

在Programming in lua中載入庫的方法是分別載入5個庫,分別是base、table、io、string、math,但是在使用中(lua5.1.3 + vs.net2003)發現io庫在載入的時候會出現錯誤,程序無法繼續執行,但不提示錯誤。

在網上查詢了一下,有些人遇到的是非法引用內存(見這裏),他的解決方法是改成上面代碼中的方式:直接載入全部庫。

這裏有一段解釋:“關於luaopen_io調用失敗的問題,在Lua的maillist裏問了一下,有人說是因爲io庫裏有些函數的運行是依賴於Lua建立的特定的環境,所以要用lua_call來調用,要麼,就直接用luaL_openlibs來引入所有標準庫。看了看幫助文檔,還有Lua的源代碼,似乎好像就是這麼回事啊!”

再查官方文檔(http://www.lua.org/manual/5.1/manual.html)中有一段:
    To have access to these libraries, the C host program should call the luaL_openlibs function, which opens all standard libraries. Alternatively, it can open them individually by calling luaopen_base (for the basic library), luaopen_package (for the package library), luaopen_string (for the string library), luaopen_table (for the table library), luaopen_math (for the mathematical library), luaopen_io (for the I/O library), luaopen_os (for the Operating System library), and luaopen_debug (for the debug library). These functions are declared in lualib.h and should not be called directly: you must call them like any other Lua C function, e.g., by using lua_call. "
最後這句的意思是:“這些函數在lualib.h中定義並且不能直接調用:你必須以其他C函數調用方式來進行調用,例如使用lua_call。”

接着是lua_call的用法:
lua_call

原型:void lua_call (lua_State *L, int nargs, int nresults);

Calls a function.
功能:調用一個方法

To call a function you must use the following protocol: first, the function to be called is pushed onto the stack; then, the arguments to the function are pushed in direct order; that is, the first argument is pushed first. Finally you call lua_call; nargs is the number of arguments that you pushed onto the stack. All arguments and the function value are popped from the stack when the function is called. The function results are pushed onto the stack when the function returns. The number of results is adjusted to nresults, unless nresults is LUA_MULTRET. In this case, all results from the function are pushed. Lua takes care that the returned values fit into the stack space. The function results are pushed onto the stack in direct order (the first result is pushed first), so that after the call the last result is on the top of the stack.

調用一個函數必須按照以下的規則:首先,將要調用的函數入棧;之後,將函數參數按順序入棧,就是說第一個參數最先入棧。最後調用lua_call;nargs是入棧的參數數。當函數被調用時彈出全部的參數和函數值。當函數返回後函數結果會壓入棧。結果的數量取決於nresults(lua_call的最後一個參數)。除非nresults的值是LUA_MULTRET。以這種方式所有的函數結果都被入棧。由Lua管理棧空間中的這些返回值。函數的結果按順序入棧(第一個元素最先入棧),所以在調用完成後最後一個參數在棧頂。

Any error inside the called function is propagated upwards (with a longjmp).
在函數調用中產生的error會被向上傳遞(使用longjmp方式)。

The following example shows how the host program may do the equivalent to this Lua code:
下面的例子展示瞭如何使宿主程序做如下lua代碼的功能:

     a = f("how", t.x, 14)

Here it is in C:
這是在C中:

     lua_getfield(L, LUA_GLOBALSINDEX, "f"); /* function to be called */
     lua_pushstring(L, "how");                        /* 1st argument */
     lua_getfield(L, LUA_GLOBALSINDEX, "t");   /* table to be indexed */
     lua_getfield(L, -1, "x");        /* push result of t.x (2nd arg) */
     lua_remove(L, -2);                  /* remove 't' from the stack */
     lua_pushinteger(L, 14);                          /* 3rd argument */
     lua_call(L, 3, 1);     /* call 'f' with 3 arguments and 1 result */
     lua_setfield(L, LUA_GLOBALSINDEX, "a");        /* set global 'a' */

如果看不明白(其實我也不明白)那就直接按照最上面的代碼中所寫的方式載入lua庫吧。

 

轉自:http://hi.baidu.com/sailor352/blog/item/ea11d243d0fd851672f05d5b.html

 

 

 

學習LUA也有一些時日了,個人認爲對於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調用的使用併爲之把正確的值放到棧上,最後注意函數完成之後會清除/移走那些位置的元素,我想應該就沒什麼問題了 

 

轉自:http://hack.gameres.com/showthread.asp?postid=149956

 

lua_gettable
lua_getglobal(L, "mytable") <== push mytable
lua_pushnumber(L, 1)        <== push key 1
lua_gettable(L, -2)         <== pop key 1, push mytable[1]

lua_settable
lua_getglobal(L, "mytable") <== push mytable
lua_pushnumber(L, 1)        <== push key 1

lua_pushstring(L, "abc")    <== push value "abc"
lua_settable(L, -3)         <== mytable[1] = "abc", pop key & value

lua_rawget:
用法同lua_gettable,但更快(因爲當key不存在時不用訪問元方法__index)

lua_rawset
:
用法同lua_settable,但更快(因爲當key不存在時不用訪問元方法__newindex)

lua_rawgeti必須爲數值鍵
lua_getglobal(L, "mytable") <== push mytable
lua_rawgeti(L, -1, 1)       <== push mytable[1],作用同下面兩行調用
--lua_pushnumber(L, 1)      <== push key 1
--lua_
rawget
(L,-2)          <== pop key 1, push mytable[1]

lua_rawseti必須爲數值鍵

lua_getglobal(L, "mytable") <== push mytable
lua_pushstring(L, "abc")    <== push value "abc"
lua_rawseti(L, -2, 1)       <== mytable[1] = "abc", pop value "abc"

lua_getfield必須爲字符串鍵
lua_getglobal(L, "mytable") <== push mytable
lua_getfield(L, -1, "x")    <== push mytable["x"],作用同下面兩行調用
--lua_pushstring(L, "x")    <== push key "x"
--lua_
gettable(L,-2)        <== pop key "x", push mytable["x"]

lua_setfield必須爲字符串鍵
lua_getglobal(L, "mytable") <== push mytable
lua_pushstring(L, "abc")    <== push value "abc"
lua_setfield(L, -2, "x")    <== mytable["x"] = "abc", pop value "abc"

轉自:http://hi.baidu.com/bidepan2023/blog/item/c53a2b0078de4d80e950cd5c.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章