userdata
Q:什么是 userdata ?
A:分为两类,full userdata 和 light userdata。Lua使用他们来表示C中的类型。
Q:两种”userdata”的区别?
A:
区别 | full userdata | light userdata |
---|---|---|
作用 | 通常用来表示C中的结构体。 一小段固定的内存区域 | 通常用来表示C中的指针(void *) |
内存管理 | 由Lua的垃圾回收器管理 | 使用者需要关心其内存 |
元表 | 有独立的元表 | 没有独立的元表 |
创建 | void *lua_newuserdata(lua_State *L, size_t size) | lua_pushlightuserdata(lua_State *L, void *p); |
例子一 light userdata
#include <stdio.h>
#include <string>
#include <iostream>
using namespace std;
extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}
typedef struct
{
int x;
int y;
int z;
}TData;
static int getAttribute(lua_State* L)
{
TData *data = (TData*)lua_touserdata(L, 1);
std::string attribute = luaL_checkstring(L, 2);
int result = 0;
if (attribute == "x")
{
result = data->x;
}
else if (attribute == "y")
{
result = data->y;
}
else
{
result = data->z;
}
lua_pushnumber(L, result);
return 1;
}
static luaL_Reg dataLib[] = {
{ "__index", getAttribute },
{ NULL, NULL }
};
void getMetaTable(lua_State* L, luaL_Reg* methods)
{
lua_pushlightuserdata(L, methods);
lua_gettable(L, LUA_REGISTRYINDEX);
if (lua_isnil(L, -1)) {
/* not found */
lua_pop(L, 1);
lua_newtable(L);
luaL_setfuncs(L, methods, 0);
lua_pushlightuserdata(L, methods);
lua_pushvalue(L, -2);
lua_settable(L, LUA_REGISTRYINDEX);
}
}
int main()
{
const char* filename = "test.lua";
lua_State *lua = luaL_newstate();
if (lua == NULL)
{
fprintf(stderr, "open lua failed");
return -1;
}
luaL_openlibs(lua);
TData input = { 123, 231, 321 };
lua_pushlightuserdata(lua, &input);
getMetaTable(lua, dataLib);
lua_setmetatable(lua, -2);
lua_setglobal(lua, "input");
if (luaL_dofile(lua, filename))
{
//luaL_error(lua, "load file %s failed", filename);
}
lua_getglobal(lua, "data");
int output = lua_tointeger(lua, -1);
std::cout << output << std::endl;
return 0;
}
lua文件
data = input.x;
print(data)
例子二 full userdata
//#include <string.h>
extern "C" {
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
}
#include <iostream>
using namespace std;
static struct StudentTag
{
char *strName; // 学生姓名
char *strNum; // 学号
int iSex; // 学生性别
int iAge; // 学生年龄
}T;
static int Student(lua_State *L)
{
size_t iBytes = sizeof(struct StudentTag);
struct StudentTag *pStudent;
pStudent = (struct StudentTag *)lua_newuserdata(L, iBytes);
//设置元表
luaL_getmetatable(L, "Student");
lua_setmetatable(L, -2);
//lua_pushnumber(L, 123);
return 1; // 新的userdata已经在栈上了
}
static int GetName(lua_State *L)
{
struct StudentTag *pStudent = (struct StudentTag *)luaL_checkudata(L, 1, "Student");
lua_pushstring(L, pStudent->strName);
return 1;
}
static int SetName(lua_State *L)
{
// 第一个参数是userdata
struct StudentTag *pStudent = (struct StudentTag *)luaL_checkudata(L, 1, "Student");
// 第二个参数是一个字符串
const char *pName = luaL_checkstring(L, 2);
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 *)luaL_checkudata(L, 1, "Student");
lua_pushinteger(L, pStudent->iAge);
return 1;
}
static int SetAge(lua_State *L)
{
struct StudentTag *pStudent = (struct StudentTag *)luaL_checkudata(L, 1, "Student");
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)
{
// 这里由你来补充
return 1;
}
static int SetSex(lua_State *L)
{
// 这里由你来补充
return 0;
}
static int GetNum(lua_State *L)
{
// 这里由你来补充
return 1;
}
static int SetNum(lua_State *L)
{
// 这里由你来补充
return 0;
}
static luaL_Reg arrayFunc_meta[] =
{
{ "getName", GetName },
{ "setName", SetName },
{ "getAge", GetAge },
{ "setAge", SetAge },
{ "getSex", GetSex },
{ "setSex", SetSex },
{ "getNum", GetNum },
{ "setNum", SetNum },
{ NULL, NULL }
};
static luaL_Reg arrayFunc[] =
{
{ "new", Student},
{ NULL, NULL }
};
extern "C" _declspec(dllexport) int luaopen_mytestlib(lua_State *L)
{
// 创建一个新的元表
luaL_newmetatable(L, "Student");
// 元表.__index = 元表
lua_pushvalue(L, -1);
lua_setfield(L, -2, "__index");
luaL_setfuncs(L, arrayFunc_meta, 0);
luaL_newlib(L, arrayFunc);
lua_pushvalue(L, -1);
lua_setglobal(L, "Sdudent"); /* the module name */
return 1;
}
lua 文件
require "mytestlib"
local objStudent = Sdudent.new()
objStudent:setName("果冻")
local strName = objStudent:getName()
print(strName )
for k,v in pairs(getmetatable(objStudent)) do
print(tostring(k),tostring(v))
end