一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

腳本之家,腳本語言編程技術及教程分享平臺!
分類導航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服務器之家 - 腳本之家 - Lua - Lua教程(五):C/C++操作Lua數組和字符串示例

Lua教程(五):C/C++操作Lua數組和字符串示例

2020-04-10 14:53junjie Lua

這篇文章主要介紹了Lua教程(五):C/C++操作Lua數組和字符串示例,本文同時還講解了如何在C/C++函數里面存儲Lua狀態,需要的朋友可以參考下

本文將介紹如何在C/C++里面操作Lua的數組和字符串類型,同時還會介紹如何在C/C++函數里面存儲Lua狀態(registry和upvalue),而registry在使用C/C++自定義類型時非常有用,可以方便地為userdata指定metatable。

C/C++操作Lua數組

Lua數組Overview

在Lua里面,數組只不過是key為整數的table而已。比如一個table為array = {12,”Hello”, “World”},它是一個數組,可以用下面的代碼來訪問它:

 

復制代碼 代碼如下:

print(array[1])  --這里會輸出array的第一個元素12。
print(array[3]) --這里會輸出array的第三個元素World

 

需要注意的一點就是:Lua的數組的下標是從1開始的。如果你使用下面的語句則會輸出nil值:

 

復制代碼 代碼如下:

print(array[0])  --輸出nil
print(array["1"])  --輸出nil(想想和array[1]的區別:一個是integer作為key,一個是字符串做為key)

 

通用Table操作方法

之前我們在教程1中介紹了如何傳遞Table給Lua,以及在教程3中介紹了如何訪問Table的數據。因為數組也是Table,所以我們可以用同樣的方式來讀取數組。

讀取數組

假設我們的Lua Table為array = {“Hello”, 1, “World”, 23.2},那么我們可以用下列函數來訪問它:

 

復制代碼 代碼如下:

void readLuaArray(lua_State *L)
{
    lua_settop(L,0); //這樣確保我們的array是放在當前棧的棧頂。
    lua_getglobal(L, "array");
    //如果前面不調用lua_settop(L,0),那我們必須要使用luaL_len(L,-1)
    int n = luaL_len(L, 1);   //luaL_len可以獲得table的元素個數
    for (int i = 1; i <= n; ++i) {
        lua_pushnumber(L, i);  //往棧里面壓入i
        lua_gettable(L, -2);  //讀取table[i],table位于-2的位置。
        //lua_rawget(L, -2);  //lua_gettable也可以用lua_rawget來替換
        cout<<lua_tostring(L, -1)<<endl;
        lua_pop(L, 1);
    }
}

 

最后輸出的結果為:

 

復制代碼 代碼如下:

"Hello", 1, "World", 23.2

 

修改數組

現在我們如果想要修改這個數組,把每一個數組的元素都變成”hehe[i]”(i = 1-n),我們看看怎么做。

 

復制代碼 代碼如下:

int writeLuaArray(lua_State *L)
{
    lua_settop(L, 0);
    lua_getglobal(L, "array");
    //確保第一個函數一個要是一個table
    luaL_checktype(L, 1, LUA_TTABLE);
    int n = luaL_len(L,1);
    for (int i = 1; i <= n; ++i) {
        lua_pushnumber(L, i);
        char buf[256];
        sprintf(buf, "hehe%d", i);
        lua_pushstring(L, buf);
//        lua_settable(L, -3);
        lua_rawset(L, -3);
    }
    return 0;
}
}

 

注意這里的lua_rawset和lua_settable是等價的,只不過lua_rawset速度更快。 最后,我們在加載完Lua腳本以后調用這兩個函數:

 

復制代碼 代碼如下:

writeLuaArray(L);
readLuaArray(L);

 

輸出結果為:

 

復制代碼 代碼如下:

readLuaArray: hehe1
readLuaArray: hehe2
readLuaArray: hehe3
readLuaArray: hehe4

 

專門的數組操作方法

因為數組一般在程序語言里面都會被特殊對待,Lua也不例外,它的C API還提供另外一種更方便高效地方法來存取數組的元素。

 

復制代碼 代碼如下:

 void lua_rawgeti (lua_State *L, int index, int key);
 void lua_rawseti (lua_State *L, int index, int key);

 

這兩個函數后面兩個參數的意思分別是:index(table在棧中的索引),key(table中數組的索引,下標從1開始) 接下來,我會通過改造上面的示例來演示這兩個API的用法。

讀取數組

因為lua_rawgeti(L,t,key)等價于:

 

復制代碼 代碼如下:

 lua_pushnumber(L, key);
 lua_rawget(L, t);

 

因此,我們的讀取代碼可以改寫成下面這樣:

 

復制代碼 代碼如下:

void readLuaArray(lua_State *L)
{
    lua_getglobal(L, "array");
    int n = luaL_len(L, -1);
    for (int i = 1; i <= n; ++i) {
        lua_rawgeti(L, 1, i);
        cout<<"readLuaArray: "<<lua_tostring(L, -1)<<endl;
        lua_pop(L, 1);
    }
}

 

修改數組

同理,lua_rawset(L,t,key)等價于

 

復制代碼 代碼如下:

lua_pushnumber(L,key); //此時的棧 table->value->key
lua_insert(L,-2);  //調用完后的棧: table->key->value (table[key]=value)
lua_rawset(L,t);

 

相應的修改數組的代碼可以修改為:

 

復制代碼 代碼如下:

int writeLuaArray(lua_State *L)
{
    lua_settop(L, 0);
    lua_getglobal(L, "array");
    //確保第一個函數一個要是一個table
    luaL_checktype(L, 1, LUA_TTABLE);
    int n = luaL_len(L,1);
    for (int i = 1; i <= n; ++i) {
        char buf[256];
        sprintf(buf, "hehe%d", i);
        lua_pushstring(L, buf);
        lua_rawseti(L, 1, i);
    }
    return 0;
}

 

C/C++操作Lua字符串

基本字符串操作

Lua C API操作字符串主要包含兩個操作:求子串(lua_pushlstring)和字符串拼接(lua_concat). 例如,我們求一個字符串s的子串[i,j],它可以表示為:

復制代碼 代碼如下:

lua_pushlstring(L, s + i, j - i + 1);


而lua_concat(L,n)則可以把當前棧頂的n個元素轉換成字符串并拼接起來,最后把結果壓入棧頂。 比如,我們想定義一個函數mycontact(…,n)可以把n個字符串拼接起來,n表示字符串的個數,那么我們的代碼可以寫成這樣:

復制代碼 代碼如下:

static int l_mycontact(lua_State* L){
    luaL_checktype(L, -1, LUA_TNUMBER);
    int n = lua_tonumber(L, -1);
    lua_pop(L, 1);
    lua_concat(L, n);
    return 1;
}

 

然后,我們需要注冊此函數到libs中去,最后在Lua里面調用此函數:

 

復制代碼 代碼如下:

print(mylib.mycontact("zilong","shanren"," meng meng"," da",4))

 

輸出結果為:

 

復制代碼 代碼如下:

zilongshanren meng meng da

 

格式化輸出

當我們想要往Lua里面寫入一個格式化字符串時,可以使用函數

 

復制代碼 代碼如下:

const char *lua_pushfstring (lua_State *L, const char *fmt, ...);

 

另外,我們還可以使用luaL_Buffer,下面是PIL書中的示例,把Lua字符串轉換成大寫:

 

復制代碼 代碼如下:

 static int str_upper (lua_State *L) {
     size_t l;
     size_t i;
     luaL_Buffer b;
     const char *s = luaL_checklstring(L, 1, &l);  //從Lua棧中取出字符串
     char *p = luaL_buffinitsize(L, &b, l); //分配一塊與取出字符串同樣大小的緩沖區
     for (i = 0; i < l; i++)
       p[i] = toupper(uchar(s[i]));
     luaL_pushresultsize(&b, l);  //把緩沖區結果轉換為字符串
     return 1;
}

 

更多的Lua Buffer操作函數如下:

 

復制代碼 代碼如下:

 void luaL_buffinit   (lua_State *L, luaL_Buffer *B);
 void luaL_addvalue   (luaL_Buffer *B);
 void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l);
 void luaL_addstring  (luaL_Buffer *B, const char *s);
 void luaL_addchar    (luaL_Buffer *B, char c);
 void luaL_pushresult (luaL_Buffer *B);

 

關于每一個函數的用法和每一個參數的含義,大家可以去Lua的Reference Manual上去查看,本文就不贅述了。

存儲Lua狀態

在C函數里面,當我們需要保存函數里面的一些狀態的時候,我們一般采用全局變量或者靜態變量的方式。但是,如果在與Lua交互時,這兩種方法都不可取。 原因有二: 1. C變量很難存儲各種各樣的Lua變量。 2. 當存在多個Lua棧的時候,就不生效了。 在Lua里面有兩種方法來存在函數內的non-local數據:registry和upvalue.

Registry方式

Register是一個Lua的全局Table,只有在Lua的C API里面可以訪問這個Table。它可以用來存儲多個Lua模塊之間的數據。 訪問Register的方式一般為:

復制代碼 代碼如下:

 lua_getfield(L, LUA_REGISTRYINDEX, "Key");


我們需要提供一個LUA_REGISTRYINDEX的“偽索引”來標識它在Lua棧中的位置。我們在操作這個table的時候,最好是使用字符串做為key,而不要使用數字來做為key。關于Registry更為實際的用法,我們會在下一篇文章中討論。

 

Upvalue方式

Upvalue主要用來存儲模塊或者函數內部的一些私有的數據,它與C語言的靜態變量有點類似。具體的用法可以參考PIL

延伸 · 閱讀

精彩推薦
  • LuaLua中table庫函數方法介紹

    Lua中table庫函數方法介紹

    這篇文章主要介紹了Lua中table庫函數方法介紹,本文講解了concat、insert、maxn、remove、sort、foreachi等方法,需要的朋友可以參考下 ...

    腳本之家2502020-04-17
  • LuaLua實現__add方法重載示例

    Lua實現__add方法重載示例

    這篇文章主要介紹了Lua實現__add方法重載示例,本文直接給出實現代碼,需要的朋友可以參考下 ...

    腳本之家7452020-04-24
  • LuaLua和C語言的交互詳解

    Lua和C語言的交互詳解

    這篇文章主要介紹了Lua和C語言的交互詳解,Lua和C語言通過棧完成交互,本文結合代碼實例詳細講解了交互的方法,需要的朋友可以參考下 ...

    果凍想3702020-04-14
  • Lua深入探究Lua中的解析表達式

    深入探究Lua中的解析表達式

    這篇文章主要介紹了深入探究Lua中的解析表達式,對于其語法部分的說明和示例都超詳細,極力推薦此文!需要的朋友可以參考下 ...

    腳本之家3542020-05-05
  • LuaLua教程(二):基礎知識、類型與值介紹

    Lua教程(二):基礎知識、類型與值介紹

    這篇文章主要介紹了Lua教程(二):基礎知識、類型與值介紹,本文講解了Hello World程序、代碼規范、全局變量、類型與值等內容,需要的朋友可以參考下 ...

    腳本之家5922020-04-28
  • LuaLua中計算、執行字符串中Lua代碼的方法

    Lua中計算、執行字符串中Lua代碼的方法

    這篇文章主要介紹了Lua中計算、執行字符串中Lua代碼的方法,類似JavaScript中eval函數的功能,在Lua中也可以實現,需要的朋友可以參考下 ...

    腳本之家6322020-04-30
  • LuaLua簡介、編譯安裝教程及變量等語法介紹

    Lua簡介、編譯安裝教程及變量等語法介紹

    這篇文章主要介紹了Lua簡介、編譯安裝教程及變量等語法介紹,本文同時講解了lua注釋語法、Lua命令行方式等內容,需要的朋友可以參考下 ...

    junjie3632020-04-14
  • LuaLua中的元方法__newindex詳解

    Lua中的元方法__newindex詳解

    這篇文章主要介紹了Lua中的元方法__newindex詳解,本文講解了查詢與更新、監控賦值、通過table給另一個table賦值等內容,需要的朋友可以參考下 ...

    笨木頭8872020-04-09
主站蜘蛛池模板: 和老外3p爽粗大免费视频 | haodiaocao几万部精彩视频 | 和日本免费不卡在线v | 91庥豆果冻天美精东蜜桃传媒 | 性xxxx欧美高清 | 69成人影院 | 国产欧美精品一区二区三区–老狼 | 国产精品模特hd在线 | 欧美人鲁交大全 | 国产一区二区三区在线观看视频 | 欧美交换乱理伦片120秒 | 日韩精品免费一区二区三区 | 国产91视频网 | 91午夜在线观看 | 好吊色网站 | 私人影院在线免费观看 | 亚洲国产在 | 日本www午夜色在线视频 | 男人猛进猛出女人下面视频 | 被肉日常np高h | 亚州在线视频 | 青草碰人人澡人人澡 | 日韩精品一二三区 | 成人国产一区二区 | 亚洲嫩模吧粉嫩粉嫩冒白浆 | 免费a视频在线观看 | 91精品国产综合久久 | 日产精品卡一卡2卡三卡乱码工厂 | 色综合视频一区二区三区 | 波多野结衣女老师 | 欧美草逼网站 | 热99这里只有精品 | 亚洲 日韩 自拍 视频一区 | 欧美日韩高清完整版在线观看免费 | 四虎最新永久在线精品免费 | 色777777女人色 | 高清毛片一区二区三区 | 嫩草影院永久入口在线观看 | 高清毛片aaaaaaaaa片 | 免费观看在线 | 9色视频在线观看 |