书本下载地址 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
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.不要修改字符串。
在Lua的C 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.3在C函数中保存状态
对一个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 && index
}
函数说明&#xff1a;
第一行NumArray* a &#61; (NumArray*)lua_touserdata(L, 1); --保证第一个参数为NumArray类型&#xff1b;否则报错。例如&#xff1a;
luaL_checkany(L, 3); --检查第三个参数&#xff0c;有值即可&#xff0c;该值为结构体中value的值&#xff1b;否则报错。例如&#xff1a;
luaL_argcheck(L, a!&#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 && index
}
前面几行的函数在前面出现&#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
#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 && index
}
//检索元素
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 && index
}
//检索数组的大小
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 && index
}
函数说明&#xff1a;
整合了之前函数setarray和getarray中一段相同代码来检查第二个索引参数。
详见上一部分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
#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 && 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
#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 && 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 userdata和light userdata之间最大的区别来自于相等性判断&#xff0c;对于一个full userdata&#xff0c;它只是与自身相等&#xff0c;而light userdata则表示为一个C指针&#xff0c;因此&#xff0c;它与所有表示同一指针的light userdata相等。再有就是light userdata不会受到垃圾收集器的管理&#xff0c;使用时就像一个普通的整型数字一样