Lua 之 userdata

在Lua中可以通过自定义类型(user data)与C语言代码更高效、更灵活的交互,从而扩展Lua能够表达的类型。

full userdata

full userdata 表示一个原始的内存块,可以存储任何东西,它是一个类似于table的object,必须事先创建(也可以被垃圾收集器回收),它也有自己的metatable,它只等于其自身。

可以为每种full userdata 创建一个唯一的元表,来辨别不同类型的userdata,每当创建了一个userdata后,就用相应的元表(放在Registry中)来标记它,而每得到一个userdata后,就检查它是否拥有正确的元表。

Lua在释放full userdata所关联的内存时,若发现userdata对应的元表还有__gc元方法,则会调用这个方法,并以userdata自身作为参数传入。利用该特性,可以再回收userdata的同时,释放与此userdata相关联的资源。

创建一个full userdata:

void *lua_newuserdata (lua_State *L, size_t size);

lua_newuserdata 分配指定大小的内存块,然后将其入栈,并返回内存块地址。

Lua没有为user data预定义任何操作,所以,对user data的操作接口仍由C接口提供,并注册到Lua环境中,供Lua使用。

下面是使用user data实现布尔数组的一个例子:

// foo.c

#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#include <limits.h> #define BITS_PER_WORD (CHAR_BIT * sizeof(int))
#define I_WORD(i) ((unsigned int)(i))/BITS_PER_WORD
#define I_BIT(i) (1 << ((unsigned int)(i)%BITS_PER_WORD)) typedef struct NumArray {
int size;
unsigned int values[];
} NumArray; int newArray(lua_State* L)
{
int i, n; n = luaL_checkint(L,); luaL_argcheck(L, n >= , , "invalid size."); size_t nbytes = sizeof(NumArray) + I_WORD(n - ) * sizeof(int); NumArray* a = (NumArray*) lua_newuserdata(L,nbytes); a->size = n; for (i = ; i < I_WORD(n - ); ++i)
a->values[i] = ; luaL_getmetatable(L, "myarray"); lua_setmetatable(L, -); return ;
} int setArray(lua_State* L)
{
//1. Lua传给该函数的第一个参数必须是userdata,该对象的元表也必须是注册表中和myarray关联的table。
//否则该函数报错并终止程序。
NumArray* a = (NumArray*)luaL_checkudata(L,,"myarray");
int index = luaL_checkint(L,) - ; luaL_checkany(L,); // there are 3 arguments
luaL_argcheck(L,a != NULL,,"'array' expected.");
luaL_argcheck(L, <= index && index < a->size,,"index out of range."); if (lua_toboolean(L,))
a->values[I_WORD(index)] |= I_BIT(index);
else
a->values[I_WORD(index)] &= ~I_BIT(index); return ;
} int getArray(lua_State* L)
{
NumArray* a = (NumArray*)luaL_checkudata(L,,"myarray");
int index = luaL_checkint(L,) - ;
luaL_argcheck(L, a != NULL, , "'array' expected.");
luaL_argcheck(L, <= index && index < a->size,,"index out of range");
lua_pushboolean(L,a->values[I_WORD(index)] & I_BIT(index));
return ;
} int getSize(lua_State* L)
{
NumArray* a = (NumArray*)luaL_checkudata(L,,"myarray");
luaL_argcheck(L,a != NULL,,"'array' expected.");
lua_pushinteger(L,a->size);
return ;
} int array2string(lua_State* L)
{
NumArray* a = (NumArray*)luaL_checkudata(L,,"myarray");
lua_pushfstring(L,"array(%d)",a->size);
return ;
} static luaL_Reg arraylib_f [] = {
{"new", newArray},
{NULL, NULL}
}; static luaL_Reg arraylib_m [] = {
{"set", setArray},
{"get", getArray},
{"size", getSize},
{"__tostring", array2string}, //print(a)时Lua会调用该元方法。
{NULL, NULL}
}; int luaopen_foo(lua_State* L)
{
//1. 创建元表,并将该元表指定给newArray函数新创建的userdata。在Lua中userdata也是以table的身份表现的。
//这样在调用对象函数时,可以通过验证其metatable的名称来确定参数userdata是否合法。
luaL_newmetatable(L,"myarray");
lua_pushvalue(L,-); //2. 为了实现面对对象的调用方式,需要将元表的__index字段指向自身,同时再将arraylib_m数组中的函数注册到
//元表中,之后基于这些注册函数的调用就可以以面向对象的形式调用了。
//lua_setfield在执行后会将栈顶的table弹出。
lua_setfield(L, -, "__index"); //将这些成员函数注册给元表,以保证Lua在寻找方法时可以定位。NULL参数表示将用栈顶的table代替第二个参数。
luaL_register(L, NULL, arraylib_m); //这里只注册的工厂方法。
luaL_register(L,"testuserdata",arraylib_f); return ;
}

编译为C模块,方便Lua调用:

gcc foo.c -shared -fPIC -o foo.so  -llua-5.1 -I /usr/local/include/ 

在Lua中使用上面定义的布尔数组:

require "foo"

local array = testuserdata.new()

print(array:size())     --

for i=, do
array:set(i, i% == )
end for i=, do
print(array:get(i))
end

在Lua中,user data是以table的形式使用。


light userdata

light userdata仅仅表示的是C指针(void*)。

light userdata 就像number类型一样,不需要创建(那自然也不会被垃圾收集器回收),也没有元表,它与所有表示同一指针的light userdata都相等;

创建一个light userdata:

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

Lua 之 userdata的更多相关文章

  1. Lua继承userdata

    http://blog.csdn.net/mywcyfl/article/details/37765751 http://blog.csdn.net/teng_ontheway/article/det ...

  2. Lua中的userdata

    [话从这里说起] 在我发表<Lua中的类型与值>这篇文章时,就有读者给我留言了,说:你应该好好总结一下Lua中的function和userdata类型.现在是时候总结了.对于functio ...

  3. Lua.LearningLua.7-userdata

    Learning Lua: 7 - userdata 1. Userdata basic "There are eight basic types in Lua: nil, boolean, ...

  4. lua: Learning Official Doc notes

    dynamically typed vars: basic types: nil, boolean, number, string, function, userdata, thread & ...

  5. [lua] mac上如何编译snapshot(检测Lua中的内存泄露)

    最近我们的unity手游频繁闪退,只要进入战斗场景,之后一段时间就会闪退,如果是在unity编辑器中则会报出not enough memory的错误!猜测应该是有内存泄漏: 由于我们使用了tolua, ...

  6. 用好lua+unity,让性能飞起来——lua与c#交互篇

    前言 在看了uwa之前发布的<Unity项目常见Lua解决方案性能比较>,决定动手写一篇关于lua+unity方案的性能优化文. 整合lua是目前最强大的unity热更新方案,毕竟这是唯一 ...

  7. Lua基础语法讲解

    Lua 是什么? Lua 是一种轻量小巧的脚本语言,用标准C语言编写并以源代码形式开放, 其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能. Lua 是巴西里约热内卢天主教大学( ...

  8. 浅析C++绑定到Lua的方法

    注:原文也在公司内部论坛上发了  概述       尽管将C++对象绑定到Lua已经有tolua++(Cocos2d-x 3.0用的就是这个).LuaBridge(我们游戏client对这个库进行了改 ...

  9. Step By Step(userdata)

    Step By Step(userdata) 在Lua中可以通过自定义类型的方式与C语言代码更高效.更灵活的交互.这里我们通过一个简单完整的示例来学习一下Lua中userdata的使用方式.需要说明的 ...

随机推荐

  1. WordPress 博客文章时间格式the_time()设置

    国外设计的WordPress 主题里的文章的时间格式是类似“十一月 21, 2010”这种格式的,而中国人习惯的是年在前,月紧跟其后,日在末尾,所以看国外的就显得很别扭,但是我们可以通过修改WP时间代 ...

  2. Java Web项目中的经典代码抽取

    前言: 众所周知的,项目开发中做得最多的无非就是增删查改(CRUD)操作.自从国内Web项目开发渐渐盛行SSH框架之后,其开发开发流程也变得更加灵活:本文就项目开发中的业务层代码作个简单的抽取,供业内 ...

  3. BIEE报表开发

    (1)报表开发实例结果图 (2)开发报表步骤: (1)创建分析 (2)创建仪表盘提示 (3)创建仪表盘并发布 登录网址,输入用户名和密码 1) 新建——>分析——>选择主题区域——> ...

  4. 【BZOJ-4561】圆的异或并 set + 扫描线

    4561: [JLoi2016]圆的异或并 Time Limit: 30 Sec  Memory Limit: 256 MBSubmit: 254  Solved: 118[Submit][Statu ...

  5. 【BZOJ-3809】Gty的二逼妹子序列 分块 + 莫队算法

    3809: Gty的二逼妹子序列 Time Limit: 80 Sec  Memory Limit: 28 MBSubmit: 1072  Solved: 292[Submit][Status][Di ...

  6. 【poj1186】 方程的解数

    http://poj.org/problem?id=1186 (题目链接) 题意 已知一个n元高次方程:   其中:x1, x2,…,xn是未知数,k1,k2,…,kn是系数,p1,p2,…pn是指数 ...

  7. VS中的代码段功能

    1.前言 开发人员不喜欢打字.如果你希望提高开发人员的生产力,减少键入的数量,这也同时减少打字稿的数量以及因此产生的编译器错误,这些都极大分散了开发人员的注意力.代码重用是开发人员收集代码的另一个原因 ...

  8. MySoft.Data 2.7.3版本的GitHub托管(ORM升级封装)

    MySoft.Data 2.7.3 dotnet ORM 版权 这里版权属于老毛:http://www.cnblogs.com/maoyong 说明 MySoft体系中的ORM组件,这里的版本为2.7 ...

  9. NuGet在Push的时候提示“远程服务器返回错误:(403)已禁用”问题解决

    在使用NuGet把包push到nuget官网的时候,提示了如下信息: Failed to process request. 'The specified API key is invalid or d ...

  10. Redis未授权访问漏洞分析

    catalog . Redis简介 . 漏洞概述 . 漏洞利用方式 . 修复方式 1. Redis简介 Relevant Link: http://www.cnblogs.com/LittleHann ...