lua與CAPI概述


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表示棧頂下面的一個,依此類推。

image

代碼測試

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的元素


免責聲明!

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



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