lua程序设计第二版 读书笔记(27-28章)

书本下载地址                     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

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

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

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

 

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

28.1 userdata

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

第一步:定义一些宏

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

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

第二步:定义结构体

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

第三步:用于新建数组的函数newarray

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

函数说明:

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

错误的调用如下:

相应的报错如下:

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

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

第四步:用于设置数组的函数setarray

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

static int setarray (lua_State *L) 
{
	NumArray* a = (NumArray*)lua_touserdata(L, 1);
	int index = luaL_checkint(L,  2)-1;//在lua中的数组下标从1开始,符合lua的习惯。
	luaL_checkany(L, 3);
	luaL_argcheck(L, a!=NULL, 1, "'array' expected");
	luaL_argcheck(L, 0<=index && indexsize, 2, "index out of range");

	if (lua_toboolean(L, 3))
	{
		a->value[I_WORD(index)] |= I_BIT(index);//设置bit
	}
	else
	{
		a->value[I_WORD(index)] &= ~I_BIT(index);//重置bit
	}
	return 0;
}

函数说明:

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

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

luaL_argcheck(La!=NULL, 1, "'array' expected");

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

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

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

(其中:&是按位与、|是按位或、~是按位非)

各操作的结果如下:

1&0=0, 0&1=0, 0&0=0, 1&1=1
1|0=1, 0|1=1, 0|0=0, 1|1=1
~1=0,~0=1

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

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

 

函数说明:

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

第六步 获取数组的大小

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

函数说明:

类似于getarray函数的分析。

第七步 初始化我们的库

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

说明:

可以在文件lauxlib.h 中找到 luaL_reg 结构体如下:

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

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

第八步 调用函数 luaL_register

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

以上都在vs中编写好了。然后生成.dll文件(array.dll

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

应用 在lua文件中

lua程序设计第二版 读书笔记(27-28章)_第1张图片

lua程序设计第二版 读书笔记(27-28章)_第2张图片

附加 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 == 8
#define BITS_PER_WORD (CHAR_BIT*sizeof(unsigned int))
//根据给定的索引来计算对应的bit位所存放的word(字)
#define I_WORD(i) ((unsigned int)(i)/BITS_PER_WORD )
//计算出一个掩码,用于访问这个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 = luaL_checkint(L, 1);
	luaL_argcheck(L, n>=1, 1, "invalid size");
	nbytes = sizeof(NumArray)+I_WORD(n-1)*sizeof(unsigned int);
	a = (NumArray*)lua_newuserdata(L, nbytes);//
	a->size = n;
	for (i=0; i<=I_WORD(n-1); i++)
	{
		a->value[i]=0;
	}
	return 1;
}

//
static int setarray(lua_State* L)
{
	NumArray* a = (NumArray*)lua_touserdata(L, 1);
	int index = luaL_checkint(L, 2)-1;
	luaL_checkany(L, 3);
	luaL_argcheck(L, a!=NULL, 1, "'array' expected");
	luaL_argcheck(L, 0<=index && indexsize, 2, "index out of range");

	if (lua_toboolean(L, 3))
	{
		a->value[I_WORD(index)] |= I_BIT(index);//设置bit
	}
	else
	{
		a->value[I_WORD(index)] &= ~I_BIT(index);//重置bit
	}
	return 0;
}
//检索元素
static int getarray(lua_State* L)
{
	NumArray* a = (NumArray*)lua_touserdata(L, 1);
	int index = luaL_checkint(L, 2)-1;
	luaL_argcheck(L, a!=NULL, 1, "'array' expected");
	luaL_argcheck(L, 0<=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 = (NumArray*)lua_touserdata(L, 1);
	luaL_argcheck(L, a!=NULL, 1, "'array' expected");
	lua_pushinteger(L, a->size);
	return 1;
}
//初始化这个库
static const struct luaL_Reg arraylib[]= 
{
	{"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 的方法是:为每种类型创建一个唯一的元表。每当创建一个userdata后,就用相应的元表来标记它。而每当得到一个userdata后,就检查它是否拥有正确的元表。(由于Lua代码不能改变userdata的元表,因此也就无法欺骗代码了。)

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

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

下面来看具体的实现(接着上一步userdata的内容):

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

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

说明:

函数 luaL_checkudata作用:

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

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

于是在之前的基础上就可以在getsize函数中修改为:

//检索数组的大小

static int getsize(lua_State* L)
{
	NumArray* a = checkarray(L);
	lua_pushinteger(L, a->size);
	return 1;
}
第二步 增加一个索引参数是否合法的函数 
static unsigned int * getindex(lua_State* L, unsigned int *mask)
{
	NumArray* a = checkarray(L);
	int index = luaL_checkint(L, 2)-1;
	luaL_argcheck(L, 0<=index && index< a->size, 2, "index out of range");
	//返回元素地址
	*mask = I_BIT(index);
	return &a->value[I_WORD(index)];
}
    

函数说明:

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

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

在之前的基础上修改setarray函数和getarray函数:

static int setarray(lua_State* L)
{
	unsigned int mask;
	unsigned int* entry = getindex(L, &mask);
	luaL_checkany(L, 3);

	if (lua_toboolean(L, 3))
	{
		*entry |= mask;//设置bit
	}
	else
	{
		*entry &= ~mask;//重置bit
	}
	return 0;
}

//检索元素
static int getarray(lua_State* L)
{
	unsigned int mask;
	unsigned int* entry = getindex(L, &mask);
	lua_pushboolean(L, *entry & mask);
	return 1;
}

//检索元素

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

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

函数说明:

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

函数原型: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;
}

函数说明:

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

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

应用 在lua文件中与前一部分相同。具体调用:

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

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

这样的结果就使内存找到破坏(如果幸运的话,可能会得到一个索引超出范围的错误)。

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

附加 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 == 8
#define BITS_PER_WORD (CHAR_BIT*sizeof(unsigned int))
//根据给定的索引来计算对应的bit位所存放的word(字)
#define I_WORD(i) ((unsigned int)(i)/BITS_PER_WORD )
//计算出一个掩码,用于访问这个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 = checkarray(L);
	int index = luaL_checkint(L, 2)-1;
	luaL_argcheck(L, 0<=index && index< a->size, 2, "index out of range");
	//返回元素地址
	*mask = 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 = luaL_checkint(L, 1);
	luaL_argcheck(L, n>=1, 1, "invalid size");
	nbytes = sizeof(NumArray)+I_WORD(n-1)*sizeof(unsigned int);
	a = (NumArray*)lua_newuserdata(L, nbytes);
	for (i=0; i<=I_WORD(n-1); i++)
	{
		a->value[i]=0;
	}

	luaL_getmetatable(L, "LuaBook.array");
	lua_setmetatable(L, -2);

	a->size = n;
	return 1;//新的userdata已在栈中
}
//
static int setarray(lua_State* L)
{
	unsigned int mask;
	unsigned int* entry = getindex(L, &mask);
	luaL_checkany(L, 3);

	if (lua_toboolean(L, 3))
	{
		*entry |= mask;//设置bit
	}
	else
	{
		*entry &= ~mask;//重置bit
	}
	return 0;
}

//检索元素
static int getarray(lua_State* L)
{
	unsigned int mask;
	unsigned int* entry = getindex(L, &mask);
	lua_pushboolean(L, *entry & mask);
	return 1;
}
//检索数组的大小
static int getsize(lua_State* L)
{
	NumArray* a = checkarray(L);
	lua_pushinteger(L, a->size);
	return 1;
}


//初始化这个库
static const struct luaL_Reg arraylib[]= 
{
	{"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[]= 
{
	{"new", newarray},
	{NULL, NULL}
};
static const luaL_Reg arraylib_m[]=
{
	{"set", setarray},
	{"get", getarray},
	{"size", getsize},
	{"__tostring", array2string},
	{NULL, NULL}
};

来替换之前的那个 

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

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

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

于是我改了

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

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

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

2文件放在同一个目录下运行:

lua程序设计第二版 读书笔记(27-28章)_第3张图片

lua程序设计第二版 读书笔记(27-28章)_第4张图片

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

//打开库的函数

int luaopen_array (lua_State *L) 
{
	luaL_newmetatable(L, "LuaBook.array");//为数组创建一个元表
	
	//元表.__index = 元表
	lua_pushvalue(L, -1);
	lua_setfield(L, -2, "__index");

	luaL_register(L, NULL, arraylib_m);
	luaL_register(L, "array", arraylib_f);
	return 1;
}

按照我之前那个“逻辑”,连luaL_register(L, NULL, arraylib_m); 这个语句都可以不要了,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 == 8
#define BITS_PER_WORD (CHAR_BIT*sizeof(unsigned int))
//根据给定的索引来计算对应的bit位所存放的word(字)
#define I_WORD(i) ((unsigned int)(i)/BITS_PER_WORD )
//计算出一个掩码,用于访问这个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 = checkarray(L);
	int index = luaL_checkint(L, 2)-1;
	luaL_argcheck(L, 0<=index && index< a->size, 2, "index out of range");
	//返回元素地址
	*mask = 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 = luaL_checkint(L, 1);
	luaL_argcheck(L, n>=1, 1, "invalid size");
	nbytes = sizeof(NumArray)+I_WORD(n-1)*sizeof(unsigned int);
	a = (NumArray*)lua_newuserdata(L, nbytes);
	a->size = n;

	for (i=0; i<=I_WORD(n-1); i++)
	{
		a->value[i]=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 = getindex(L, &mask);
	luaL_checkany(L, 3);

	if (lua_toboolean(L, 3))
	{
		*entry |= mask;//设置bit
	}
	else
	{
		*entry &= ~mask;//重置bit
	}
	return 0;
}

//检索元素
static int getarray(lua_State* L)
{
	unsigned int mask;
	unsigned int* entry = getindex(L, &mask);
	lua_pushboolean(L, *entry & mask);
	return 1;
}
//检索数组的大小
static int getsize(lua_State* L)
{
	NumArray* a = checkarray(L);
	lua_pushinteger(L, a->size);
	return 1;
}

//初始化这个库
static const struct luaL_Reg arraylib[]= 
{
	//{"new", newarray},
	//{"set", setarray},
	//{"get", getarray},
	//{"size", getsize},
	{NULL, NULL}
};

//
static const struct luaL_Reg arraylib_f[]= 
{
	{"set", setarray},
	{"get", getarray},
	{"size", getsize},
	{"__tostring", array2string},
	{"new", newarray},
	{NULL, NULL}
};
//
static const luaL_Reg arraylib_m[]=
{
	//{"set", setarray},
	//{"get", getarray},
	//{"size", getsize},
	//{"__tostring", array2string},
	{NULL, NULL}
};
//
int array2string (lua_State *L) 
{
	NumArray *a = 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 = 元表
	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),可以简单地写成a[i]

实例如下:

说明:直接沿用上一节的array.dll 文件,即这2个在同一目录下即可。

运行结果:

lua程序设计第二版 读书笔记(27-28章)_第5张图片

 

28.5 轻量级userdata light userdata

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

 

你可能感兴趣的:(Lua,Lua,笔记,读书笔记,第二版,lua程序)