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