最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

 更新時間:2015年04月30日 10:36:45   投稿:junjie  
這篇文章主要介紹了Lua教程(二十一):編寫C函數(shù)的技巧,本文講解了數(shù)組操作、字符串操作、在C函數(shù)中保存狀態(tài)等內容,需要的朋友可以參考下

1. 數(shù)組操作:

    在Lua中,“數(shù)組”只是table的一個別名,是指以一種特殊的方法來使用table。出于性能原因,Lua的C API為數(shù)組操作提供了專門的函數(shù),如:
 

復制代碼 代碼如下:

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

    以上兩個函數(shù)分別用于讀取和設置數(shù)組中的元素值。其中index參數(shù)表示待操作的table在棧中的位置,key表示元素在table中的索引值。由于這兩個函數(shù)均為原始操作,比涉及元表的table訪問更快。通常而言,作為數(shù)組使用的table很少會用到元表。

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

復制代碼 代碼如下:

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

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

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

 2. 字符串操作:

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

復制代碼 代碼如下:

    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函數(shù),并將格式化后的字符串壓入棧中。和sprintf的格式說明符不同的是,該函數(shù)只支持%%(表示字符%)、%s(表示字符串)、%d(表示整數(shù))、%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函數(shù),其功能類似于Lua中的".."操作符,用于連接(并彈出)棧頂?shù)膎個值,然后壓入連接后的結果。其原型為:
    void  lua_concat(lua_State *L, int n);
    參數(shù)n表示棧中待連接的字符串數(shù)量。該函數(shù)會調用元方法。然而需要說明的是,如果連接的字符串數(shù)量較少,該函數(shù)可以很好的工作,反之,則會帶來性能問題。為此,Lua API提供了另外一組函數(shù)專門解決由此而帶來的性能問題,見如下代碼示例:

復制代碼 代碼如下:

#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;
    //檢查參數(shù)第一個參數(shù)是否為字符串,同時返回字符串的指針及長度。
    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將一個字符放入緩沖。除該函數(shù)之外,Lua的輔助庫還提供了直接添加字符串的函數(shù),如:
 

復制代碼 代碼如下:

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

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

    void luaL_addvalue(luaL_Buffer* b);
   

    3. 在C函數(shù)中保存狀態(tài):
    Lua API提供了三種方式來保存非局部變量,即注冊表、環(huán)境和upvalue。
    1). 注冊表:
    注冊表是一個全局的table,只能被C代碼訪問。通常用于保存多個模塊間的共享數(shù)據(jù)。我們可以通過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). 環(huán)境:
    如果需要保存一個模塊的私有數(shù)據(jù),即模塊內各函數(shù)需要共享的數(shù)據(jù),應該使用環(huán)境。我們可以通過LUA_ENVIRONINDEX索引值來訪問環(huán)境。
 

復制代碼 代碼如下:

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

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

//模塊內獲取環(huán)境數(shù)據(jù)的函數(shù)
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);  //創(chuàng)建一個新的表用于環(huán)境
    lua_replace(L,LUA_ENVIRONINDEX); //將剛剛創(chuàng)建并壓入棧的新表替換為當前模塊的環(huán)境表。
    luaL_register(L,"testenv",myfuncs);
    return 1;
}
 

Lua測試代碼如下。

復制代碼 代碼如下:

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

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

#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);
    //賦值一份棧頂?shù)臄?shù)據(jù),以便于后面的替換操作。
    lua_pushvalue(L,-1);
    //該函數(shù)將棧頂?shù)臄?shù)據(jù)替換到upvalue(1)中的值。同時將棧頂數(shù)據(jù)彈出。
    lua_replace(L,lua_upvalueindex(1));
    //lua_pushinteger(L,++value)中壓入的數(shù)據(jù)仍然保留在棧中并返回給Lua。
    return 1;
}

extern "C" int newCounter(lua_State* L)
{
    //壓入一個upvalue的初始值0,該函數(shù)必須先于lua_pushcclosure之前調用。
    lua_pushinteger(L,0);
    //壓入閉包函數(shù),參數(shù)1表示該閉包函數(shù)的upvalue數(shù)量。該函數(shù)返回值,閉包函數(shù)始終位于棧頂。
    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
--]]

相關文章

  • Lua中調用C++函數(shù)實例

    Lua中調用C++函數(shù)實例

    這篇文章主要介紹了Lua中調用C++函數(shù)實例,本文是Lua和C++通信系列文章的最后一篇,需要的朋友可以參考下
    2014-09-09
  • Lua table簡明總結

    Lua table簡明總結

    這篇文章主要介紹了Lua table簡明總結,table是lua唯一的數(shù)據(jù)結構,table 是 lua 中最重要的數(shù)據(jù)類型,本文詳細講解了table的相關知識,需要的朋友可以參考下
    2014-10-10
  • 在Lua程序中使用SQLite的教程

    在Lua程序中使用SQLite的教程

    這篇文章主要介紹了在Lua程序中使用SQLite的教程,包括建立連接到基本的查詢等一些操作,需要的朋友可以參考下
    2015-05-05
  • Lua中實現(xiàn)遞歸刪除一個文件夾

    Lua中實現(xiàn)遞歸刪除一個文件夾

    這篇文章主要介紹了Lua中實現(xiàn)遞歸刪除一個文件夾,本文給出了使用C++和使用純LUA兩種方式實現(xiàn),需要的朋友可以參考下
    2015-01-01
  • Lua中類的實現(xiàn)

    Lua中類的實現(xiàn)

    Lua中沒有類的概念,但我們可以利用Lua本身的語言特性來實現(xiàn)類。 下文將詳細的解釋在Lua中實現(xiàn)類的原理
    2015-04-04
  • Redis教程(五):Set數(shù)據(jù)類型

    Redis教程(五):Set數(shù)據(jù)類型

    這篇文章主要介紹了Redis教程(五):Set數(shù)據(jù)類型,本文講解了Set數(shù)據(jù)類型概述、相關命令、命令使用示例、應用范圍等內容,需要的朋友可以參考下
    2015-04-04
  • Lua時間轉化的幾個小例子

    Lua時間轉化的幾個小例子

    這篇文章主要介紹了Lua時間轉化的幾個小例子,本文直接給出3段例子代碼,需要的朋友可以參考下
    2015-06-06
  • Lua教程(九):元表與元方法詳解

    Lua教程(九):元表與元方法詳解

    這篇文章主要介紹了Lua教程(九):元表與元方法詳解,本文講解了算術類的元方法、關系類的元方法、庫定義的元方法、table訪問的元方法等內容,需要的朋友可以參考下
    2015-04-04
  • Lua基本語法

    Lua基本語法

    Lua是相當簡單易學,本篇文章來給大家稍微講一下Lua的語法,不會長篇累牘得把Lua的所有語法都講一遍,這里通過以下幾點來講Lua語言的基礎語法。
    2015-05-05
  • lua實現(xiàn)的2048小游戲

    lua實現(xiàn)的2048小游戲

    之前給大家分享了好幾個語言版本的2048了,今天再給大家分享一個lua腳本實現(xiàn)的2048小游戲,小伙伴們參考下吧。
    2015-03-03

最新評論

宿迁市| 惠水县| 个旧市| 贵德县| 遵义县| 怀仁县| 湄潭县| 溧阳市| 桃源县| 武清区| 金川县| 手机| 汶上县| 古蔺县| 彰化市| 黑水县| 新宾| 神农架林区| 冀州市| 汶上县| 海门市| 田东县| 会泽县| 湖口县| 广汉市| 商城县| 招远市| 彰武县| 上高县| 年辖:市辖区| 广州市| 新蔡县| 台东市| 县级市| 大冶市| 瓦房店市| 长丰县| 青阳县| 鸡西市| 交城县| 高碑店市|