亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > 綜合 > 正文

Lua教程(二十一):編寫C函數的技巧

2024-07-21 23:04:46
字體:
來源:轉載
供稿:網友

1. 數組操作:

    在Lua中,“數組”只是table的一個別名,是指以一種特殊的方法來使用table。出于性能原因,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中的索引值。由于這兩個函數均為原始操作,比涉及元表的table訪問更快。通常而言,作為數組使用的table很少會用到元表。

 

    見如下代碼示例和關鍵性注釋:

復制代碼 代碼如下:

#include <stdio.h>
#include <string.h>
#include <lua.hpp>
#include <lauxlib.h>
#include <lualib.h>

 

extern "C" int mapFunc(lua_State* L)
{
    //檢查Lua調用代碼中傳遞的第一個參數必須是table。否則將引發錯誤。
    luaL_checktype(L,1,LUA_TTABLE);
    luaL_checktype(L,2,LUA_TFUNCTION);
    //獲取table中的字段數量,即數組的元素數量。
    int n = lua_objlen(L,1);
    //Lua中的數組起始索引習慣為1,而不是C中的0。
    for (int i = 1; i <= n; ++i) {
        lua_pushvalue(L,2);  //將Lua參數中的function(第二個參數)的副本壓入棧中。
        lua_rawgeti(L,1,i);  //壓入table[i]
        lua_call(L,1,1);     //調用function(table[i]),并將函數結果壓入棧中。
        lua_rawseti(L,1,i);  //table[i] = 函數返回值,同時將返回值彈出棧。
    }

    //無結果返回給Lua代碼。
    return 0;
}

 

 2. 字符串操作:

    當一個C函數從Lua收到一個字符串參數時,必須遵守兩條規則:不要在訪問字符串時從棧中將其彈出,不要修改字符串。在Lua的C API中主要提供了兩個操作Lua字符串的函數,即:
 

復制代碼 代碼如下:

    void  lua_pushlstring(lua_State *L, const char *s, size_t l);
    const char* lua_pushfstring(lua_State* L, const char* fmt, ...);
 

    第一個API用于截取指定長度的子字符串,同時將其壓入棧中。而第二個API則類似于C庫中的sprintf函數,并將格式化后的字符串壓入棧中。和sprintf的格式說明符不同的是,該函數只支持%%(表示字符%)、%s(表示字符串)、%d(表示整數)、%f(表示Lua中的number)及%c(表示字符)。除此之外,不支持任何例如寬度和精度的選項。

 

 

復制代碼 代碼如下:

#include <stdio.h>
#include <string.h>
#include <lua.hpp>
#include <lauxlib.h>
#include <lualib.h>

 

extern "C" int splitFunc(lua_State* L)
{
    const char* s = luaL_checkstring(L,1);
    const char* sep = luaL_checkstring(L,2); //分隔符
    const char* e;
    int i = 1;
    lua_newtable(L); //結果table
    while ((e = strchr(s,*sep)) != NULL) {
        lua_pushlstring(L,s,e - s);  //壓入子字符串。
        //將剛剛壓入的子字符串設置給table,同時賦值指定的索引值。
        lua_rawseti(L,-2,i++);      
        s = e + 1;
    }
    //壓入最后一個子串
    lua_pushstring(L,s);
    lua_rawseti(L,-2,i);
    return 1; //返回table。
}

 

 Lua API中提供了lua_concat函數,其功能類似于Lua中的".."操作符,用于連接(并彈出)棧頂的n個值,然后壓入連接后的結果。其原型為:
    void  lua_concat(lua_State *L, int n);
    參數n表示棧中待連接的字符串數量。該函數會調用元方法。然而需要說明的是,如果連接的字符串數量較少,該函數可以很好的工作,反之,則會帶來性能問題。為此,Lua API提供了另外一組函數專門解決由此而帶來的性能問題,見如下代碼示例:

復制代碼 代碼如下:

#include <stdio.h>
#include <string.h>
#include <lua.hpp>
#include <lauxlib.h>
#include <lualib.h>

 

extern "C" int strUpperFunc(lua_State* L)
{
    size_t len;
    luaL_Buffer b;
    //檢查參數第一個參數是否為字符串,同時返回字符串的指針及長度。
    const char* s = luaL_checklstring(L,1,&len);
    //初始化Lua的內部Buffer。
    luaL_buffinit(L,&b);
    //將處理后的字符依次(luaL_addchar)追加到Lua的內部Buffer中。
    for (int i = 0; i < len; ++i)
        luaL_addchar(&b,toupper(s[i]));
    //將該Buffer及其內容壓入棧中。
    luaL_pushresult(&b);
    return 1;
}

 

  使用緩沖機制的第一步是聲明一個luaL_Buffer變量,并用luaL_buffinit來初始化它。初始化后,就可通過luaL_addchar將一個字符放入緩沖。除該函數之外,Lua的輔助庫還提供了直接添加字符串的函數,如:
 

復制代碼 代碼如下:

    void luaL_addlstring(luaL_Buffer* b, const char* s, size_t len);
    void luaL_addstring(luaL_Buffer* b, const char* s);
 

    最后luaL_pushresult會更新緩沖,并將最終的字符串留在棧頂。通過這些函數,就無須再關心緩沖的分配了。但是在追加的過程中,緩沖會將一些中間結果放到棧中。因此,在使用時要留意此細節,只要保證壓入和彈出的次數相等既可。Lua API還提供一個比較常用的函數,用于將棧頂的字符串或數字也追加到緩沖區中,函數原型為:
 
復制代碼 代碼如下:

    void luaL_addvalue(luaL_Buffer* b);
   

    3. 在C函數中保存狀態:
    Lua API提供了三種方式來保存非局部變量,即注冊表、環境和upvalue。
    1). 注冊表:
    注冊表是一個全局的table,只能被C代碼訪問。通常用于保存多個模塊間的共享數據。我們可以通過LUA_REGISTRYINDEX索引值來訪問注冊表。

 

 

復制代碼 代碼如下:

 #include <stdio.h>
#include <string.h>
#include <lua.hpp>
#include <lauxlib.h>
#include <lualib.h>

 

void registryTestFunc(lua_State* L)
{
    lua_pushstring(L,"Hello");
    lua_setfield(L,LUA_REGISTRYINDEX,"key1");
    lua_getfield(L,LUA_REGISTRYINDEX,"key1");
    printf("%s/n",lua_tostring(L,-1));
}

int main()
{
    lua_State* L = luaL_newstate();
    registryTestFunc(L);
    lua_close(L);
    return 0;
}
 

 

 2). 環境:
    如果需要保存一個模塊的私有數據,即模塊內各函數需要共享的數據,應該使用環境。我們可以通過LUA_ENVIRONINDEX索引值來訪問環境。
 

復制代碼 代碼如下:

 #include <lua.hpp>
#include <lauxlib.h>
#include <lualib.h>

 

//模塊內設置環境數據的函數
extern "C" int setValue(lua_State* L)
{
    lua_pushstring(L,"Hello");
    lua_setfield(L,LUA_ENVIRONINDEX,"key1");
    return 0;
}

//模塊內獲取環境數據的函數
extern "C" int getValue(lua_State* L)
{
    lua_getfield(L,LUA_ENVIRONINDEX,"key1");
    printf("%s/n",lua_tostring(L,-1));
    return 0;
}

static luaL_Reg myfuncs[] = {
    {"setValue", setValue},
    {"getValue", getValue},
    {NULL, NULL}
};


extern "C" __declspec(dllexport)
int luaopen_testenv(lua_State* L)
{
    lua_newtable(L);  //創建一個新的表用于環境
    lua_replace(L,LUA_ENVIRONINDEX); //將剛剛創建并壓入棧的新表替換為當前模塊的環境表。
    luaL_register(L,"testenv",myfuncs);
    return 1;
}
 

 

Lua測試代碼如下。

復制代碼 代碼如下:

 require "testenv"
 
 print(testenv.setValue())
 print(testenv.getValue())
 --輸出為:Hello

    3). upvalue:
    upvalue是和特定函數關聯的,我們可以將其簡單的理解為函數內的靜態變量。
復制代碼 代碼如下:

#include <lua.hpp>
#include <lauxlib.h>
#include <lualib.h>

 

extern "C" int counter(lua_State* L)
{
    //獲取第一個upvalue的值。
    int val = lua_tointeger(L,lua_upvalueindex(1));
    //將得到的結果壓入棧中。
    lua_pushinteger(L,++val);
    //賦值一份棧頂的數據,以便于后面的替換操作。
    lua_pushvalue(L,-1);
    //該函數將棧頂的數據替換到upvalue(1)中的值。同時將棧頂數據彈出。
    lua_replace(L,lua_upvalueindex(1));
    //lua_pushinteger(L,++value)中壓入的數據仍然保留在棧中并返回給Lua。
    return 1;
}

extern "C" int newCounter(lua_State* L)
{
    //壓入一個upvalue的初始值0,該函數必須先于lua_pushcclosure之前調用。
    lua_pushinteger(L,0);
    //壓入閉包函數,參數1表示該閉包函數的upvalue數量。該函數返回值,閉包函數始終位于棧頂。
    lua_pushcclosure(L,counter,1);
    return 1;
}

static luaL_Reg myfuncs[] = {
    {"counter", counter},
    {"newCounter", newCounter},
    {NULL, NULL}
};


extern "C" __declspec(dllexport)
int luaopen_testupvalue(lua_State* L)
{
    luaL_register(L,"testupvalue",myfuncs);
    return 1;
}

 

    Lua測試代碼如下。

 

復制代碼 代碼如下:

require "testupvalue"

 

func = testupvalue.newCounter();
print(func());
print(func());
print(func());

func = testupvalue.newCounter();
print(func());
print(func());
print(func());

--[[ 輸出結果為:
1
2
3
1
2
3
--]]


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产精品狠色婷| 日韩av中文字幕在线免费观看| 国产精彩精品视频| 欧美激情视频在线观看| 日韩高清a**址| 韩国三级电影久久久久久| 日韩欧美在线观看视频| 成人情趣片在线观看免费| 亚洲第一黄色网| 自拍偷拍亚洲精品| 国产精品国产自产拍高清av水多| 日韩精品免费在线| xxxx欧美18另类的高清| 久久久久久噜噜噜久久久精品| 57pao成人国产永久免费| 91精品国产色综合久久不卡98| 日韩欧美在线免费观看| 亚洲视频免费一区| 亚洲男人的天堂在线播放| 亚洲国产精品字幕| 最新91在线视频| 国产精品av网站| 国产精品视频久久久| 色www亚洲国产张柏芝| 亚洲欧美国产精品久久久久久久| 国外色69视频在线观看| 亚洲一区二区久久久| 亚洲精品久久久久久久久久久久| 91九色蝌蚪国产| 欧美色道久久88综合亚洲精品| 国产亚洲欧美日韩美女| 亚洲精品永久免费| 亚洲va久久久噜噜噜久久天堂| 亚洲福利视频免费观看| 亚洲欧美综合图区| 亚洲午夜激情免费视频| 夜夜嗨av色一区二区不卡| 亚洲香蕉av在线一区二区三区| 国产精品视频在线播放| 国产丝袜精品视频| 97在线免费视频| 国产欧美日韩丝袜精品一区| 久久免费成人精品视频| 中文字幕国产亚洲| 日韩美女主播视频| 高清日韩电视剧大全免费播放在线观看| 国产69久久精品成人| 日韩中文字幕在线精品| 日韩大胆人体377p| 精品毛片三在线观看| 久久久久99精品久久久久| 欧美一级淫片播放口| 欧美亚洲在线播放| 国产欧美在线视频| 秋霞成人午夜鲁丝一区二区三区| 中文字幕精品www乱入免费视频| 欧美激情亚洲视频| 91香蕉嫩草影院入口| 国产欧美久久一区二区| 亚洲精品网址在线观看| 日韩女在线观看| 色樱桃影院亚洲精品影院| 亚洲第一二三四五区| 久久久久国产视频| 欧美理论电影网| 国产精品一区二区三区免费视频| 国产免费一区二区三区香蕉精| 久久综合伊人77777蜜臀| 国产精品白嫩初高中害羞小美女| 国产美女搞久久| 国产日本欧美一区| 欧美乱人伦中文字幕在线| 亚洲精品小视频| 高清欧美电影在线| 韩国19禁主播vip福利视频| 国产成人在线一区二区| 欧美视频13p| 91美女福利视频高清| 国产精品久在线观看| 热久久免费视频精品| 欧美一级bbbbb性bbbb喷潮片| 97超级碰在线看视频免费在线看| 精品美女国产在线| 日韩精品中文字幕久久臀| 日韩精品在线播放| 91av在线不卡| 国产日韩欧美日韩大片| 日韩av电影在线免费播放| 奇米四色中文综合久久| 欧美巨大黑人极品精男| 日本成人免费在线| 久久综合免费视频影院| 欧美剧在线观看| 国产精品高清免费在线观看| 亚洲一区二区三区乱码aⅴ| 久久久久久久av| 亚洲福利视频二区| 国产亚洲人成网站在线观看| 97久久超碰福利国产精品…| 亚洲精品乱码久久久久久金桔影视| 午夜精品一区二区三区在线视| 欧美日韩中文字幕在线| 日韩中文在线中文网在线观看| 国产精品日本精品| 日韩精品极品在线观看播放免费视频| 国产精品96久久久久久又黄又硬| 亚洲自拍偷拍区| 国产亚洲一区二区在线| 91超碰中文字幕久久精品| 欧美性猛交xxxx乱大交蜜桃| 国内精久久久久久久久久人| 在线国产精品播放| 国产欧美一区二区| 亚洲国产精品国自产拍av秋霞| 亚洲欧美日韩在线高清直播| 欧美有码在线视频| 日产精品99久久久久久| 久久激情视频久久| 国产成人短视频| 亚洲综合大片69999| 国产精品丝袜视频| 国产精品电影观看| 欧美日韩国产91| 午夜精品免费视频| 色小说视频一区| 日本精品一区二区三区在线| 亚洲国产精品99久久| 96精品久久久久中文字幕| 在线观看国产成人av片| 国产精品久久久久久久美男| 欧美一级淫片丝袜脚交| 亚洲男人天堂网| 亚洲精品suv精品一区二区| 日韩在线www| 亚洲乱码国产乱码精品精| 日韩一中文字幕| 色青青草原桃花久久综合| 97超碰色婷婷| 欧美一级淫片丝袜脚交| 亚洲欧美第一页| 亚洲的天堂在线中文字幕| 中文字幕国产亚洲2019| 精品久久久香蕉免费精品视频| 欧美在线视频观看| 亚洲自拍偷拍在线| 欧美国产精品人人做人人爱| 亚洲精品久久久久久久久久久久久| 亚洲人成伊人成综合网久久久| 亚洲欧美制服中文字幕| 韩国视频理论视频久久| 最近中文字幕mv在线一区二区三区四区| 亚洲欧美中文日韩在线| 欧美黑人一区二区三区| 国产综合久久久久久| 欧美丰满少妇xxxxx| 91精品国产自产在线观看永久| 91av视频在线播放| www.亚洲一区| 91精品国产高清久久久久久91| 国产精品美女免费看| 国产亚洲欧美另类中文| 久久网福利资源网站| 欧美成人精品在线播放| 国产91精品久久久久|