热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

lua程序设计第二版读书笔记(2728章)

书本下载地址http:download.csdn.netdetailmyy20125349646本部分下载地址http:download.csdn.netdetailmyy201

书本下载地址                     http://download.csdn.net/detail/myy2012/5349646

本部分下载地址              http://download.csdn.net/detail/myy2012/5433541

 

ps:最近几个月在公司都没事做,然后最近几天一直想着要不要辞职。最后还是跟领导说了,领导说再呆阵子吧,上级的上级。

      瞬间我也不懂了,纠结了好久。哎,不管不管,不过也好几天没看这边书了。补上。快看完了。

 

 

lua程序设计第二版 读书笔记(1-4章)
第一章 开始
第二章 类型与值
第三章 表达式
第四章 语句
http://blog.csdn.net/myy2012/article/details/8900424

lua程序设计第二版 读书笔记(5-8章)
第五章 函数
第六章 深入函数
第七章 迭代器与泛型for
第八章 编译执行与错误
http://blog.csdn.net/myy2012/article/details/8906466

lua程序设计第二版 读书笔记(9-10章)
第九章 协同程序
第十章 完整的实例
http://blog.csdn.net/myy2012/article/details/8911206

lua程序设计第二版 读书笔记(11-14章)
第十一章 数据结构
第十二章 数据文件与持久性
第十三章 元表metatable与元方法meatmethod
第十四章 环境
http://blog.csdn.net/myy2012/article/details/8914457

lua程序设计第二版 读书笔记(15-17章)
第十五章 模块与包
第十六章  面向对象编程
第十七章 弱引用 table
http://blog.csdn.net/myy2012/article/details/8921632

lua程序设计第二版 读书笔记(18-21章)
第十八章 数学库
第十九章 table库
第二十章 字符串库
第二十一章 IO库
http://blog.csdn.net/myy2012/article/details/8925895

lua程序设计第二版 读书笔记(22-23章)
第二十二章 操作系统库
第二十三章 调试库
http://blog.csdn.net/myy2012/article/details/8930181

 

 

 


第二十七章  编写C函数的技术

 

27.1 数组操作

API为数组操作提供了两个函数:

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

其中:index表示table在栈中的位置,key表示元素在table中的位置。

假设t为正数,那么调用函数lua_rawgeti(L, t, key)等价于

  lua_pushnumber(L, key);lua_rawget(L, t);

 调用函数lua_seti(L, t, key) 等价于

  lua_pushnumber(L, key);lua_insert(L, -2);lua_rawset(L, t);

 

27.2 字符串操作

当一个C函数从Lua收到一个字符串参数时,必须遵守两条规则:1.不要在访问字符串时从栈中弹出它;2.不要修改字符串。

LuaC API中主要提供了两个操作Lua字符串的函数,即:

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函数,将格式化后的字符串压入栈中。该函数只支持%%(表示字符%)%s(表示字符串)%d(表示整数)%f(表示Lua中的number)%c(表示字符)

27.3C函数中保存状态

对一个Lua函数来说,有3种地方可以存放非局部的数据(全局变量、函数环境、非局部变量)。而C API也提供了3种地方来保存这类数据(注册表、环境、upvalue)。

1. 注册表

  注册表是一个全局的table,它只能被C代码访问。通常用于保存多个模块间的共享数据。

注册表总是位于一个“伪索引”上,这个值由LUA_REGISTRYINDEX定义。例如:为了获取注册表中key为“Key”的值:lua_getfield( L, LUA_REGISTRYINDEX, “Key”);

在注册表中不应使用数字类型的key,因为这种类型的key是被“引用系统”所保留的。这个系统是由辅助库中的一系列繁琐组成的,它可以在向一个table 存储value时,忽略如何创建一个唯一的key

int  r = luaL_ref( L, LUA_REGISTRYINDEX);

Lua API中提供了专门的用来连接字符串的函数lua_concat。等价于Lua中的..操作符:自动将数字转换成字符串,如果有必要的时候还会自动调用metamethods。另外,她可以同时连接多个字符串。调用lua_concat(L,n)将连接(同时会出栈)栈顶的n个值,并将最终结果放到栈顶。

另一个有用的函数是lua_pushfstring:

  const char *lua_pushfstring (lua_State *L,const char *fmt, ...);

2. C函数的环境

Lua中注册的所有C函数都有自己的环境table,一个函数可以像访问注册表那样通过一个伪索引(LUA_ENVIRONINDEX)来访问它的环境table

通常,使用这些函数的方法与在Lua模块中使用环境的方法差不多。即先为模块创建一个新的table,然后使模块中的所有函数都共享这个table。也就是修改主程序的环境,然后所有新建的函数都会自动地套用这个新环境。附上C语言中设置环境的代码:

  int luaopen_foo( lua_State* L){lua_newtable(L);lua_replace(L, LUA_ENVIRONINDEZX);luaL_register( L, <库名>, <函数列表>);}

3. upvalue

注册表提供了全局变量的存储&#xff0c;环境提供了模块变量的存储&#xff0c;而upvaue机制实现了一种类似于C语言中静态变量的机制&#xff0c;这种变量只在一个特定的函数可见。

每当在Lua中创建一个函数时&#xff0c;都可以将任意数量的upvalue与整个函数相关联&#xff0c;每个upvalue都可以保存一个Lua的值&#xff1b;以后&#xff0c;在调用这个函数时&#xff0c;就可以通过伪索引来访问这些upvalue

将这种C函数与upvalue的关联称为closure。一个C closure 类似于Lua closure&#xff0c;closure可以用同一个函数代码来创建多个closure&#xff0c;每个closure可以拥有不同的upvalue

 


第二十八章 用户自定义类型

28.1 userdata

这一部分结合书中给出的函数来分析。

第一步&#xff1a;定义一些宏

//无符号整型bit数量 CHAR_BIT &#61;&#61; 8&#xff08;limits.h 中有定义&#xff09;
#define BITS_PER_WORD (CHAR_BIT*sizeof(unsigned int))
//根据给定的索引来计算对应的bit位所存放的word&#xff08;字&#xff09;
#define I_WORD(i) ((unsigned int)(i)/BITS_PER_WORD )
//计算出一个掩码&#xff0c;用于访问这个word的正确bit
#define I_BIT(i) (i<<((unsigned int )(i)%BITS_PER_WORD))

Ps&#xff1a;不要把这些宏想的那么可怕那么复杂&#xff0c;其实在32位的机子上&#xff0c;第一个为16&#xff0c;第二个为i/16&#xff08;16的倍数取整的结果&#xff09;&#xff0c;第三个为i%16&#xff08;i左移 “对16求余的结果” 位&#xff09;

第二步&#xff1a;定义结构体


typedef struct NumArray
{int size;unsigned int value[1];
} NumArray;

第三步&#xff1a;用于新建数组的函数newarray

static int newarray (lua_State *L)
{unsigned int i;int n;size_t nbytes;NumArray* a;n &#61; luaL_checkint(L, 1);luaL_argcheck(L, n>&#61;1, 1, "invalid size");nbytes &#61; sizeof(NumArray)&#43;I_WORD(n-1)*sizeof(unsigned int);a &#61; (NumArray*)lua_newuserdata(L, nbytes);//a->size &#61; n;for (i&#61;0; i<&#61;I_WORD(n-1); i&#43;&#43;)a->value[i]&#61;0;--数组中的value初始化为0return 1;
}

函数说明&#xff1a;

第五、六行-- 检查传入的参数是否为整型&#xff0c;且数值是否大于1

错误的调用如下&#xff1a;

相应的报错如下&#xff1a;

第八行中--函数lua_newuserdata 会根据指定的大小分配一块内存&#xff0c;并将对应的userdata压入栈中&#xff0c;最后返回这个内存块的地址。&#xff08;函数原型&#xff1a;void * lua_newuserdata( lua_State * L, size_t size);&#xff09;

lua_newuserdata函数按照指定的大小分配一块内存&#xff0c;将对应的userdatum放到栈内&#xff0c;并返回内存块的地址。

第四步&#xff1a;用于设置数组的函数setarray

为了存储元素&#xff0c;我们使用类似array.set(array, index, value)调用&#xff0c;后面我们将看到如何使用metatables来支持常规的写法array[index] &#61; value

static int setarray (lua_State *L)
{NumArray* a &#61; (NumArray*)lua_touserdata(L, 1);int index &#61; luaL_checkint(L, 2)-1;//在lua中的数组下标从&#xff11;开始&#xff0c;符合lua的习惯。luaL_checkany(L, 3);luaL_argcheck(L, a!&#61;NULL, 1, "&#39;array&#39; expected");luaL_argcheck(L, 0<&#61;index && indexsize, 2, "index out of range");if (lua_toboolean(L, 3)){a->value[I_WORD(index)] |&#61; I_BIT(index);//设置bit}else{a->value[I_WORD(index)] &&#61; ~I_BIT(index);//重置bit}return 0;
}

函数说明&#xff1a;

第一行NumArraya &#61; (NumArray*)lua_touserdata(L, 1); --保证第一个参数为NumArray类型&#xff1b;否则报错。例如&#xff1a;

luaL_checkany(L, 3); --检查第三个参数&#xff0c;有值即可&#xff0c;该值为结构体中value的值&#xff1b;否则报错。例如&#xff1a;


luaL_argcheck(La!&#61;NULL, 1, "&#39;array&#39; expected");

luaL_argcheck(L, 0<&#61;index && index<a->size, 2, "index out of range");

函数luaL_argcheck 用于检查传入的参数是否满足一定的条件&#xff1b;否则报错。例如&#xff1a;

设置bit和重置bit 涉及到部分汇编的东西&#xff0c;相信接触的人都知道。|&#61;  和 &&#61; ~  

&#xff08;其中&#xff1a;&是按位与、|是按位或、~是按位非&#xff09;

各操作的结果如下&#xff1a;

1&0&#61;0, 0&1&#61;0, 0&0&#61;0, 1&1&#61;1
1|0&#61;1, 0|1&#61;1, 0|0&#61;0, 1|1&#61;1
~1&#61;0,~0&#61;1

第五步 获取数组中value的函数


static int getarray (lua_State *L)
{NumArray* a &#61; (NumArray*)lua_touserdata(L, 1);int index &#61; luaL_checkint(L, 2)-1;luaL_argcheck(L, a!&#61;NULL, 1, "&#39;array&#39; expected");luaL_argcheck(L, 0<&#61;index && indexsize, 2, "index out of range");lua_pushboolean(L, a->value[I_WORD(index)] & I_BIT(index));return 1;
}

 


函数说明&#xff1a;

前面几行的函数在前面出现&#xff0c;语句 lua_pushboolean(L, a->value[I_WORD(index)] & I_BIT(index));  根据索引号返回相应value中的值。例如&#xff1a;

第六步 获取数组的大小


static int getsize (lua_State *L)
{NumArray* a &#61; (NumArray*)lua_touserdata(L, 1);luaL_argcheck(L, a!&#61;NULL, 1, "&#39;array&#39; expected");lua_pushinteger(L, a->size);return 1;
}

函数说明&#xff1a;

类似于getarray函数的分析。


第七步 初始化我们的库

static const struct luaL_reg arraylib [] &#61;
{
{"new", newarray},
{"set", setarray},
{"get", getarray},
{"size", getsize},
{NULL, NULL}
};

说明&#xff1a;

可以在文件lauxlib.h 中找到 luaL_reg 结构体如下&#xff1a;

给我们定义的函数取个来个相关联的名字。

最后一个{NULL, NULL} 则是提示库中函数定义的结束。

第八步 调用函数 luaL_register


int luaopen_array (lua_State *L)
{luaL_register(L, "array", arraylib);
return 1;
}

以上都在vs中编写好了。然后生成.dll文件&#xff08;array.dll&#xff09;

lua文件放在同一个目录下即可。



应用 在lua文件中



附加 vs中完整的代码  整个文件已经在下载那边给出地址了

http://download.csdn.net/detail/myy2012/5433541

 


#ifdef __cplusplus
extern "C"
{
#endif#include
#include
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
#pragma comment(lib, "lua51.lib")
}#include //无符号整型bit数量CHAR_BIT &#61;&#61; 8
#define BITS_PER_WORD (CHAR_BIT*sizeof(unsigned int))
//根据给定的索引来计算对应的bit位所存放的word&#xff08;字&#xff09;
#define I_WORD(i) ((unsigned int)(i)/BITS_PER_WORD )
//计算出一个掩码&#xff0c;用于访问这个word的正确bit
#define I_BIT(i) (i<<((unsigned int )(i)%BITS_PER_WORD))typedef struct NumArray
{int size;unsigned int value[1];
} NumArray;//创建一个新的布尔数组
static int newarray(lua_State* L)
{unsigned int i;int n;size_t nbytes;NumArray* a;n &#61; luaL_checkint(L, 1);luaL_argcheck(L, n>&#61;1, 1, "invalid size");nbytes &#61; sizeof(NumArray)&#43;I_WORD(n-1)*sizeof(unsigned int);a &#61; (NumArray*)lua_newuserdata(L, nbytes);//a->size &#61; n;for (i&#61;0; i<&#61;I_WORD(n-1); i&#43;&#43;){a->value[i]&#61;0;}return 1;
}//
static int setarray(lua_State* L)
{NumArray* a &#61; (NumArray*)lua_touserdata(L, 1);int index &#61; luaL_checkint(L, 2)-1;luaL_checkany(L, 3);luaL_argcheck(L, a!&#61;NULL, 1, "&#39;array&#39; expected");luaL_argcheck(L, 0<&#61;index && indexsize, 2, "index out of range");if (lua_toboolean(L, 3)){a->value[I_WORD(index)] |&#61; I_BIT(index);//设置bit}else{a->value[I_WORD(index)] &&#61; ~I_BIT(index);//重置bit}return 0;
}
//检索元素
static int getarray(lua_State* L)
{NumArray* a &#61; (NumArray*)lua_touserdata(L, 1);int index &#61; luaL_checkint(L, 2)-1;luaL_argcheck(L, a!&#61;NULL, 1, "&#39;array&#39; expected");luaL_argcheck(L, 0<&#61;index && indexsize, 2, "index out of range");lua_pushboolean(L, a->value[I_WORD(index)] & I_BIT(index));return 1;
}
//检索数组的大小
static int getsize(lua_State* L)
{NumArray* a &#61; (NumArray*)lua_touserdata(L, 1);luaL_argcheck(L, a!&#61;NULL, 1, "&#39;array&#39; expected");lua_pushinteger(L, a->size);return 1;
}
//初始化这个库
static const struct luaL_Reg arraylib[]&#61;
{{"new", newarray},{"set", setarray},{"get", getarray},{"size", getsize},{NULL, NULL}
};
//
extern "C" __declspec(dllexport)int luaopen_array(lua_State* L)
{luaL_register(L, "array", arraylib);return 1;

}

28.2  元表

一种辨别不同类型的userdata 的方法是&#xff1a;为每种类型创建一个唯一的元表。每当创建一个userdata后&#xff0c;就用相应的元表来标记它。而每当得到一个userdata后&#xff0c;就检查它是否拥有正确的元表。&#xff08;由于Lua代码不能改变userdata的元表&#xff0c;因此也就无法欺骗代码了。&#xff09;

另外还需要有个地方来存储这个行的元表&#xff0c;然后才能用它来创建新的userdata&#xff0c;并检查给定的userdata是否具有正确的类型。

Lua中&#xff0c;通常习惯是将所有新的C类型注册到注册表中&#xff0c;以一个类型名作为key&#xff0c;元表作为value。&#xff08;由于注册表中还有其他的内容&#xff0c;所有必须小心地选择类型名&#xff0c;以避免与key冲突。

下面来看具体的实现&#xff08;接着上一步userdata的内容&#xff09;&#xff1a;

第一步 增加一个检查参数的宏

#define checkarray(L) (NumArray*)luaL_checkudata(L, 1, "LuaBook.array")

说明&#xff1a;

函数 luaL_checkudata作用&#xff1a;

可以检查栈中指定位置上是否为一个userdata&#xff0c;并且是否具有与给定名称相匹配的元表。&#xff08;返回这个userdata地址&#xff0c;否则引发一个错误。&#xff09;

函数原型&#xff1a; void *luaL_checkudata (lua_State *L, int index, const char *tname);

于是在之前的基础上就可以在getsize函数中修改为&#xff1a;

//检索数组的大小

static int getsize(lua_State* L)
{NumArray* a &#61; checkarray(L);lua_pushinteger(L, a->size);return 1;
}

第二步 增加一个索引参数是否合法的函数 

static unsigned int * getindex(lua_State* L, unsigned int *mask)
{NumArray* a &#61; checkarray(L);int index &#61; luaL_checkint(L, 2)-1;luaL_argcheck(L, 0<&#61;index && indexsize, 2, "index out of range");//返回元素地址*mask &#61; I_BIT(index);return &a->value[I_WORD(index)];
}

函数说明&#xff1a;

整合了之前函数setarraygetarray中一段相同代码来检查第二个索引参数。

详见上一部分userdata中的相关函数说明。

在之前的基础上修改setarray函数和getarray函数&#xff1a;

static int setarray(lua_State* L)
{unsigned int mask;unsigned int* entry &#61; getindex(L, &mask);luaL_checkany(L, 3);if (lua_toboolean(L, 3)){*entry |&#61; mask;//设置bit}else{*entry &&#61; ~mask;//重置bit}return 0;
}//检索元素
static int getarray(lua_State* L)
{unsigned int mask;unsigned int* entry &#61; getindex(L, &mask);lua_pushboolean(L, *entry & mask);return 1;
}

//检索元素

static int getarray(lua_State* L)
{unsigned int mask;unsigned int* entry &#61; getindex(L, &mask);lua_pushboolean(L, *entry & mask);return 1;
}

第三步 在newarray函数分钟添加2行luaL_getmetatable(L, "LuaBook.array");lua_setmetatable(L, -2);

函数说明&#xff1a;

使其能为所有新建的数组设置这个元表&#xff0c;在注册表中检索与他那么关联的元表。

函数原型&#xff1a;void lua_getmetatable( lua_State * L, const char * tname);

第四步 修改打开库的函数

//打开库的函数
int luaopen_array (lua_State *L)
{luaL_newmetatable(L, "LuaBook.array");//为数组创建一个元表luaL_register(L, "array", arraylib);return 1;
}

函数说明&#xff1a;

创建一个新的table用作元表&#xff0c;并将其压入栈顶&#xff0c;然后将这个table与注册表中的指定名称关联起来。

函数原型&#xff1a;int luaL_newmetatable(lua_State*L, const char * tname);

应用 在lua文件中与前一部分相同。具体调用&#xff1a;

不过此时试图这样调用 array.get(io.stdin, 10),就会得到一个错误的消息&#xff1a;

而在之前的userdata中则 编译通过。

这样的结果就使内存找到破坏&#xff08;如果幸运的话&#xff0c;可能会得到一个索引超出范围的错误&#xff09;。

但对于有些Lua库来说&#xff0c;这种行为是不可接受的。问题的原因不在于如何使用一个C程序库&#xff0c;而在与程序库不应破坏C数据或在Lua中导致核心转储&#xff08;Core Dump&#xff09;。


附加 vs中完整的代码 在下载地址中有

http://download.csdn.net/detail/myy2012/5433541


#ifdef __cplusplus
extern "C"
{
#endif#include
#include
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
#pragma comment(lib, "lua51.lib")
}#include //无符号整型bit数量CHAR_BIT &#61;&#61; 8
#define BITS_PER_WORD (CHAR_BIT*sizeof(unsigned int))
//根据给定的索引来计算对应的bit位所存放的word&#xff08;字&#xff09;
#define I_WORD(i) ((unsigned int)(i)/BITS_PER_WORD )
//计算出一个掩码&#xff0c;用于访问这个word的正确bit
#define I_BIT(i) (i<<((unsigned int )(i)%BITS_PER_WORD))
//检查参数是否合法
#define checkarray(L) (NumArray*)luaL_checkudata(L, 1, "LuaBook.array")typedef struct NumArray
{int size;unsigned int value[1];
} NumArray;//检查索引的参数是否合法
static unsigned int * getindex(lua_State* L, unsigned int *mask)
{NumArray* a &#61; checkarray(L);int index &#61; luaL_checkint(L, 2)-1;luaL_argcheck(L, 0<&#61;index && indexsize, 2, "index out of range");//返回元素地址*mask &#61; I_BIT(index);return &a->value[I_WORD(index)];
}static int newarray (lua_State *L)
{unsigned int i;int n;size_t nbytes;NumArray* a;n &#61; luaL_checkint(L, 1);luaL_argcheck(L, n>&#61;1, 1, "invalid size");nbytes &#61; sizeof(NumArray)&#43;I_WORD(n-1)*sizeof(unsigned int);a &#61; (NumArray*)lua_newuserdata(L, nbytes);for (i&#61;0; i<&#61;I_WORD(n-1); i&#43;&#43;){a->value[i]&#61;0;}luaL_getmetatable(L, "LuaBook.array");lua_setmetatable(L, -2);a->size &#61; n;return 1;//新的userdata已在栈中
}
//
static int setarray(lua_State* L)
{unsigned int mask;unsigned int* entry &#61; getindex(L, &mask);luaL_checkany(L, 3);if (lua_toboolean(L, 3)){*entry |&#61; mask;//设置bit}else{*entry &&#61; ~mask;//重置bit}return 0;
}//检索元素
static int getarray(lua_State* L)
{unsigned int mask;unsigned int* entry &#61; getindex(L, &mask);lua_pushboolean(L, *entry & mask);return 1;
}
//检索数组的大小
static int getsize(lua_State* L)
{NumArray* a &#61; checkarray(L);lua_pushinteger(L, a->size);return 1;
}//初始化这个库
static const struct luaL_Reg arraylib[]&#61;
{{"new", newarray},{"set", setarray},{"get", getarray},{"size", getsize},{NULL, NULL}
};
//
extern "C" __declspec(dllexport)//打开库的函数
int luaopen_array (lua_State *L)
{luaL_newmetatable(L, "LuaBook.array");//为数组创建一个元表luaL_register(L, "array", arraylib);return 1;
}

28.3面向对象的访问

郁闷的是我按照书上的例子写了2

static const struct luaL_Reg arraylib_f[]&#61;
{{"new", newarray},{NULL, NULL}
};
static const luaL_Reg arraylib_m[]&#61;
{{"set", setarray},{"get", getarray},{"size", getsize},{"__tostring", array2string},{NULL, NULL}
};

来替换之前的那个 


static const struct luaL_Reg arraylib[]&#61;
{{"new", newarray},{"set", setarray},{"get", getarray},{"size", getsize},{NULL, NULL}
};

竟然在lua文件中运行出错。

然后我在想为什么我在lua文件中运行的new那一行不会报错呢&#xff1f;

于是我改了


static const struct luaL_Reg arraylib_f[]&#61;
{{"set", setarray},{"get", getarray},{"size", getsize},{"__tostring", array2string},{"new", newarray},{NULL, NULL}
};

把初始化库中的函数对于的东西跟new放到一起了。

结果在lua中编译类似面向对象的语句竟然可以编译通过。我也不知道为什么&#xff0c;谁知道的说一声啊。

2文件放在同一个目录下运行&#xff1a;

跟前面一节中相比较除了刚刚说的对库的初始化不同外&#xff0c;还有在函数 

//打开库的函数

int luaopen_array (lua_State *L)
{luaL_newmetatable(L, "LuaBook.array");//为数组创建一个元表//元表.__index &#61; 元表lua_pushvalue(L, -1);lua_setfield(L, -2, "__index");luaL_register(L, NULL, arraylib_m);luaL_register(L, "array", arraylib_f);return 1;
}

按照我之前那个“逻辑”&#xff0c;连luaL_register(L, NULL, arraylib_m); 这个语句都可以不要了&#xff0c;arraylib_m 也 不要定义了。

附加这部分的代码 在给出的下载地址中有

http://download.csdn.net/detail/myy2012/5433541


#ifdef __cplusplus
extern "C"
{
#endif#include
#include
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
#pragma comment(lib, "lua51.lib")
}#include //无符号整型bit数量CHAR_BIT &#61;&#61; 8
#define BITS_PER_WORD (CHAR_BIT*sizeof(unsigned int))
//根据给定的索引来计算对应的bit位所存放的word&#xff08;字&#xff09;
#define I_WORD(i) ((unsigned int)(i)/BITS_PER_WORD )
//计算出一个掩码&#xff0c;用于访问这个word的正确bit
#define I_BIT(i) (i<<((unsigned int )(i)%BITS_PER_WORD))
//检查参数是否合法
#define checkarray(L) (NumArray*)luaL_checkudata(L, 1, "LuaBook.array")typedef struct NumArray
{int size;unsigned int value[1];
} NumArray;//函数声明
int array2string (lua_State *L);//检查索引的参数是否合法
static unsigned int * getindex(lua_State* L, unsigned int *mask)
{NumArray* a &#61; checkarray(L);int index &#61; luaL_checkint(L, 2)-1;luaL_argcheck(L, 0<&#61;index && indexsize, 2, "index out of range");//返回元素地址*mask &#61; I_BIT(index);return &a->value[I_WORD(index)];
}static int newarray (lua_State *L)
{unsigned int i;int n;size_t nbytes;NumArray* a;n &#61; luaL_checkint(L, 1);luaL_argcheck(L, n>&#61;1, 1, "invalid size");nbytes &#61; sizeof(NumArray)&#43;I_WORD(n-1)*sizeof(unsigned int);a &#61; (NumArray*)lua_newuserdata(L, nbytes);a->size &#61; n;for (i&#61;0; i<&#61;I_WORD(n-1); i&#43;&#43;){a->value[i]&#61;0;}luaL_getmetatable(L, "LuaBook.array");lua_setmetatable(L, -2);return 1;//新的userdata已在栈中
}
//
static int setarray(lua_State* L)
{unsigned int mask;unsigned int* entry &#61; getindex(L, &mask);luaL_checkany(L, 3);if (lua_toboolean(L, 3)){*entry |&#61; mask;//设置bit}else{*entry &&#61; ~mask;//重置bit}return 0;
}//检索元素
static int getarray(lua_State* L)
{unsigned int mask;unsigned int* entry &#61; getindex(L, &mask);lua_pushboolean(L, *entry & mask);return 1;
}
//检索数组的大小
static int getsize(lua_State* L)
{NumArray* a &#61; checkarray(L);lua_pushinteger(L, a->size);return 1;
}//初始化这个库
static const struct luaL_Reg arraylib[]&#61;
{//{"new", newarray},//{"set", setarray},//{"get", getarray},//{"size", getsize},{NULL, NULL}
};//
static const struct luaL_Reg arraylib_f[]&#61;
{{"set", setarray},{"get", getarray},{"size", getsize},{"__tostring", array2string},{"new", newarray},{NULL, NULL}
};
//
static const luaL_Reg arraylib_m[]&#61;
{//{"set", setarray},//{"get", getarray},//{"size", getsize},//{"__tostring", array2string},{NULL, NULL}
};
//
int array2string (lua_State *L)
{NumArray *a &#61; checkarray(L);lua_pushfstring(L, "array(%d)", a->size);return 1;
}
//
extern "C" __declspec(dllexport)//打开库的函数
int luaopen_array (lua_State *L)
{luaL_newmetatable(L, "LuaBook.array");//为数组创建一个元表//元表.__index &#61; 元表lua_pushvalue(L, -1);lua_setfield(L, -2, "__index");//luaI_openlib(L, NULL, arraylib_m, 0);//luaI_openlib(L, "array", arraylib_f, 0);//luaL_register(L, NULL, arraylib_m);luaL_register(L, "array", arraylib_f);return 1;
}

28.4 数组访问

另一种面向对象写法是使用常规数组访问的写法。

相当于写a:get(i)&#xff0c;可以简单地写成a[i]

实例如下&#xff1a;

说明&#xff1a;直接沿用上一节的array.dll 文件&#xff0c;即这2个在同一目录下即可。

运行结果&#xff1a;

 



28.5 轻量级userdata &#xff08;light userdata&#xff09;

  之前介绍的是full userdata&#xff0c;Lua还提供了另一种轻量级userdata(light userdata)。事实上&#xff0c;轻量级userdata仅仅表示的是C指针的值&#xff0c;即(void*)。由于它只是一个值&#xff0c;所以不用创建。如果需要将一个轻量级userdata放入栈中&#xff0c;调用lua_pushlightuserdata即可。full userdatalight userdata之间最大的区别来自于相等性判断&#xff0c;对于一个full userdata&#xff0c;它只是与自身相等&#xff0c;而light userdata则表示为一个C指针&#xff0c;因此&#xff0c;它与所有表示同一指针的light userdata相等。再有就是light userdata不会受到垃圾收集器的管理&#xff0c;使用时就像一个普通的整型数字一样


 


推荐阅读
author-avatar
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有