lua——userdata使用

userdata說明:

0、Lua中使用userdata類型來表示在C中定義的類型。userdata只是提供了一塊原始的內存區域,可以用來存儲任何東西,並且,在lua中userdata沒有任何預定義的操作。在C中調用函數lua_newuserdata會根據指定的大小分配一塊內存,並將相應的userdata壓入棧中,最後返回這個內存塊的地址:void *lua_newuserdata(lua_State*L,size_t size)。

    1、實質在C中定義lua的userdata,與定義C模塊完全類似,只不過通常這時需要通過調用lua_newuserdata來告訴lua分配一塊額外的內存,而在內存所有相關的操作都是在C中的定義的,實質就是C模塊中的接口。注意這塊分配的額外內存是由Lua垃圾收集器來管理的,無須關心起釋放等情況。

    2、在實現一個Lua的程序庫或userdate,必須保證該庫或userdata的接口不應破壞C數據或在Lua中導致core dump。

    3、可以爲每種userdata創建一個唯一的元表,來辨別不同類型的userdata,每當創建了一個userdata後,就用相應的元表來標記它,而每得到一個userdata後,就檢查它是否擁有正確的元表,注意Lua代碼中不能改變userdata的元表(當能增加已有元表的屬性,比如對元表key爲__index賦值)。通常是將這個元表存儲在註冊表中,也類型名作爲key,元表爲value。輔助庫提供了一些函數來實現這些:

     int luaL_newmetatable(lua_State*L, const char *tname);

     void luaL_getmetatable(lua_State *L,const char *tnaem); 

     void *luaL_checkudata(lua_State*L,int index,const char *tname);

    4、輕量級userdata是一種表示C指針的值(即void*),要將一個輕量級userdata放入棧中,只需要調用lua_pushlightuserdata即可。輕量級userdata只是一個指針而已。它沒有元表,就像數字一樣,輕量級userdata無須受垃圾收集器的管理。

    5、Lua在釋放完全userdata所關聯的內存時,若發現userdata對應的元表還有__gc元方法,則會調用這個方法,並以userdata自身作爲參數傳入。利用該特性,可以再回收userdata的同時,釋放與此userdata相關聯的資源。

 

 

 

 

 

 

 

full userdata

 

static struct StudentTag

{

         char *strName; // 學生姓名

         char *strNum; // 學號

         int iSex; // 學生性別

         int iAge; // 學生年齡

};

 

//lua 中通過調用這個接口來得到 pStudent指針

static int Student(lua_State *L)

{

         size_t iBytes = sizeof(struct StudentTag);

         struct StudentTag *pStudent;

         pStudent = (struct StudentTag *)lua_newuserdata(L, iBytes);

 

         return 1; // 新的userdata已經在棧上了

}

 

static int GetName(lua_State *L)

{

         struct StudentTag *pStudent = (struct StudentTag *)lua_touserdata(L, 1);

         luaL_argcheck(L, pStudent != NULL, 1, "Wrong Parameter");

         lua_pushstring(L, pStudent->strName);

         return 1;

}

 

static int SetName(lua_State *L)

{

         // 第一個參數是userdata

         struct StudentTag *pStudent = (struct StudentTag *)lua_touserdata(L, 1);

         luaL_argcheck(L, pStudent != NULL, 1, "Wrong Parameter");

 

         // 第二個參數是一個字符串

         const char *pName = luaL_checkstring(L, 2);//檢查第2個參數是不是string,並返回參數值

         luaL_argcheck(L, pName != NULL && pName != "", 2, "Wrong Parameter");

 

         pStudent->strName = (char *)pName;

         return 0;

}

 

static int GetAge(lua_State *L)

{

         struct StudentTag *pStudent = (struct StudentTag *)lua_touserdata(L, 1);

         luaL_argcheck(L, pStudent != NULL, 1, "Wrong Parameter");

         lua_pushinteger(L, pStudent->iAge);

         return 1;

}

static int SetAge(lua_State *L)

{

         struct StudentTag *pStudent = (struct StudentTag *)lua_touserdata(L, 1);

         luaL_argcheck(L, pStudent != NULL, 1, "Wrong Parameter");

 

         int iAge = luaL_checkinteger(L, 2);

         luaL_argcheck(L, iAge >= 6 && iAge <= 100, 2, "Wrong Parameter");

         pStudent->iAge = iAge;

         return 0;

}

static int GetSex(lua_State *L)

{

         // 這裏由你來補充

         struct StudentTag *pStudent = (struct StudentTag *)lua_touserdata(L, 1);

         luaL_argcheck(L, pStudent != NULL, 1, "get wrong arg from lua");

         lua_pushnumber(L, pStudent->iSex);//通過C++操作把數據放入到堆棧中,  1表示男 2表示女

         return 1;

}

 

static int SetSex(lua_State *L)

{

         // 這裏由你來補充

         struct StudentTag *pStudent = (struct StudentTag *)lua_touserdata(L, 1);

         luaL_argcheck(L, pStudent != NULL, 1, "get wrong arg from lua");

 

         int iSex = luaL_checkinteger(L, 2);

         luaL_argcheck(L, iSex == 1 || iSex == 2, 2, "get wrong arg from lua");

         pStudent->iSex = iSex;

 

         return 0;

}

 

static int GetNum(lua_State *L)

{

         // 這裏由你來補充

 

 

 

 

 

 

         return 1;

}

 

static int SetNum(lua_State *L)

{

         // 這裏由你來補充

 

 

 

 

         return 0;

}

 

static struct luaL_reg arrayFunc[] =

{

         {"new", Student},//註冊成爲Student的接口

         {"getName", GetName},

         {"setName", SetName},

         {"getAge", GetAge},

         {"setAge", SetAge},

         {"getSex", GetSex},

         {"setSex", SetSex},

         {"getNum", GetNum},

         {"setNum", SetNum},

         {NULL, NULL}

};

 

int luaopen_userdatademo1(lua_State *L)

{

         luaL_register(L, "Student", arrayFunc);

         luaL_dofile(L, "main.lua");

         return 1;

}

 

 

 

 

 

.lua文件代碼:

local objStudent = Student.new()

Student.setName(objStudent, "果凍想")

Student.setAge(objStudent, 15)

Student.setSex(objStudent, 2)

 

local strName = Student.getName(objStudent)

local iAge = Student.getAge(objStudent)

local iSex = Student.getSex(objStudent)

 

 

 

print("1")

print(strName)

print(iAge)

print("2")

print("iSex" .. iSex)

 

 

 

 

 

輕量級userdata

輕量級userdata是一種表示C指針的值(即void *)。由於它是一個值,所以不用創建它。要將一個輕量級userdata放入棧中,只需要調用lua_pushlightuserdata即可。

 

void lua_pushlightuserdata(lua_State *L,void *p);

儘管兩種userdata在名稱上差不多,但它們之間還是存在很大不同的。輕量級userdata不是緩衝,只是一個指針而已。它也沒有元表,就像數字一樣,輕量級userdata不受到垃圾收集器的管理。

 

輕量級userdata的真正用途是相等性判斷。一個完全userdata是一個對象,它只與自身相等。而一個輕量級userdata則表示了一個C指針的值。因此,它與所有表示同一個指針的輕量級userdata相等。可以將輕量級userdata用於查找Lua中的C對象。

 

// 壓入輕量級userdata,一個static變量的地址

static char key = 'k';

lua_pushlightuserdata(L, (void *)&key);

lua_pushstring(L, "JellyThink");

lua_settable(L, LUA_REGISTRYINDEX);

由於靜態變量的地址在一個進程中具有唯一性,所以絕對不會出現重複key的問題。

 

// 從註冊表中取對應的值

lua_pushlightuserdata(L, (void *)&key);

lua_gettable(L,  LUA_REGISTRYINDEX);

 

 

 

 

C++中代碼:

 

         lua_State *L = luaL_newstate();

         if (L)

         {

                   luaL_openlibs(L);

         }

 

         lua_pushnumber(L, 20);

         lua_setglobal(L, "dde");

 

         static char key = 'k';

         lua_pushlightuserdata(L, (void *)&key);

 

         lua_setglobal(L, "ddee");

         luaL_dofile(L, "tabletest.lua");

 

 

.lua代碼

print("sdfe" .. dde)

print("type" .. type(ddee))

 

結果:

 
————————————————
版權聲明:本文爲CSDN博主「從小就愛吃肉」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/dugaoda/article/details/50259497

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