欢迎访问 Lu程序设计

C/C++使用Lu脚本字符串键树

1 说明

    要演示本文的例子,你必须下载Lu64脚本系统。本文的例子需要lu64.dll、lu64.lib、C格式的头文件lu64.h,相信你会找到并正确使用这几个文件。

    用C/C++编译器创建一个控制台应用程序,复制本文的例子代码直接编译运行即可。

2 关于Lu字符串键树

    参考Lu编程指南,在Lu中,表达式、常量、函数、任意自定义数据等等,所有的东西都放到一棵键树中。Lu键树保存数据的格式如下(数据与键的名称、长度、类型是一一对应的关系):

KeyStr:键的名称(char *KeyStr)。区分大小写,可包含任意字符,包括NULL('\0')。
ByteNum:键的长度(luINT ByteNum)。ByteNum>0
KeyType:键的类型(luKEY KeyType)。

    键的类型KeyType有两种:公有键(KeyType>=luPubKey_User)和私有健(KeyType<=luPriKey_User)。

    Lu所支持的程序可能很复杂,程序可以动态加载许多功能模块,每一个模块都可以向Lu键树注册数据,若注册为公有键,则该键可以被任意的功能模块所删除;若注册为私有健,则只有自己可以删除该键。

    键的类型可以用函数LockKey加锁。锁定键的类型后,该键只能存储一种数据类型。如果没有锁定键的类型,则该键可以存储任意多种类型的数据。

    公有键luPubKey_User和私有健luPriKey_User用来存放一些约定的键,不能加锁。例如,核心库约定使用如下函数输出信息:

typedef void (_stdcall * luMessage) (wchar_t *); //显示Lu信息的函数指针

    主程序或其他模块,需设计如下输出信息的函数:

void _stdcall LuMessage(wchar_t *pWStr)  //输出Lu信息,该函数注册到Lu,由Lu及二级函数调用
{
    ... ...
}

    然后将该函数用InsertKey("\0\0\0\0\0\0\0\0",8,luPubKey_User,LuMessage,NULL,NULL,1,&NowKey)注册到Lu(注意,使用的是公有键luPubKey_User)。约定Lu及所有二级函数都使用该函数显示信息。任一线程均可根据需要设置该函数。查询该函数的方法为:

luMessage pMessage=(luMessage)SearchKey("\0\0\0\0\0\0\0\0",8,luPubKey_User);

    Lu键的类型如表1所示。

表1 Lu键的类型

类别 键的类型 标识符 生成对象 查询对象 销毁对象 说明
系统键

255~-199

        系统使用。
-128~-255 -200 luPriKey_UserSearch       用户可查询和删除的私有健最大值 键的类型由系统定义,但用户可以使用。键的类型均被锁定。都是动态数据类型,即系统定义的动态数据类型。
-252 luDynData_realarray NewSysObj SearchKey/GetArray DeleteKey 动态64位实数数组
-253 luDynData_intarray NewSysObj SearchKey/GetArray DeleteKey 动态64位整数数组
-254 luDynData_string NewSysObj SearchKey/GetStr DeleteKey 动态字符串
-255 luDynData_lu NewSysObj SearchKey DeleteKey 动态Lu数据
用户键 256 luPubKey_User InsertKey/GetBufObj SearchKey DeleteKey 公有键。用来存放一些约定的键。不能加锁。
-256 luPriKey_User InsertKey/GetBufObj SearchKey DeleteKey 私有键。用来存放一些约定的键。不能加锁。
> 256 > luPubKey_User InsertKey/GetBufObj SearchKey DeleteKey 由用户定义的公有键。均大于256。可加锁。
< -256 < luPriKey_User InsertKey/GetBufObj SearchKey DeleteKey 由用户定义的私有键。均小于-256。可加锁。
-1073741824 luPoiKey_User InsertKey/GetBufObj SearchKey DeleteKey 指针键最小值。小于luPoiKey_User的非指针键只有自己可以销毁。指针键不仅要求键的类型KeyType>=luPoiKey_User,而且要求用InsertKey插入键时键的长度为4,但一定要取-1。

    如果用C/C++设计一个较大的程序,该程序允许加载许多来自不同的人用不同的语言设计的模块,Lu键树对私有数据的保护功能将会大有用武之地。

    虽然Lu键树是为Lu脚本系统设计的,但实际上Lu键树可用单独使用。本例C/C++使用Lu键树管理数据的例子,并没有使用Lu脚本表达式(函数)的编译运算功能。

    本文的例子中,代码1演示了公有键(KeyType>=luPubKey_User)的用法;代码2演示了指针型私有键(KeyType>=luPoiKey_User)的用法;代码3演示了非指针型私有键(KeyType<luPoiKey_User)的用法。

3 代码

代码1:演示公有键

#include <stdio.h>
#include <malloc.h>
#include "lu64.h"

#pragma comment( lib, "lu64.lib" )

int kkk;	//为避免编译器优化而设置

typedef struct pub_k	//将注册为公有键
{
	int k;
} pub_k;
void _stdcall Del_pub_k(void *me)	//销毁pub_k的函数
{
	free(me);
}

typedef struct pub_d	//将注册为公有键
{
	double d;
} pub_d;
void _stdcall Del_pub_d(void *me)	//销毁pub_d的函数
{
	kkk=0;	//避免编译器将Del_pub_d和Del_pub_k优化为同一个函数

	free(me);
}
LuData _stdcall OpLock_pub_d(luINT m,LuData *Para,void *hFor,int theOperator)	//pub_d的运算符重载函数
{
	LuData a;

	a.BType=luStaData_nil; a.VType=luStaData_nil; a.x=0;	//不对pub_d类型的对象做运算,总返回nil
	return a;
}

#define key_no_lock	luPubKey_User+10	//不对该公有键加锁
#define key_lock		luPubKey_User+20	//将对该公有键加锁

void main(void)
{
	pub_k *pk;
	pub_d *pd;
	void *NowKey;		//返回已存在的键值

	if(!InitLu()) return;	//初始化Lu

	pk=(pub_k *)malloc(sizeof(pub_k));
	pk->k=10;
	pd=(pub_d *)malloc(sizeof(pub_d));
	pd->d=1.23;
	InsertKey("my_k",4,key_no_lock,pk,Del_pub_k,NULL,1,&NowKey);	//在Lu键树中注册键值
	InsertKey("my_d",4,key_no_lock,pd,Del_pub_d,NULL,1,&NowKey);	//在Lu键树中注册键值

	pk=(pub_k *)SearchKey("my_k",4,key_no_lock);	//在Lu键树中查找键值
	if(pk) printf("%d\n",pk->k);
	pd=(pub_d *)SearchKey("my_d",4,key_no_lock);	//在Lu键树中查找键值
	if(pd) printf("%f\n",pd->d);

	DeleteKey("my_k",4,key_no_lock,NULL,0);	//在Lu键树中删除键值
	DeleteKey("my_d",4,key_no_lock,NULL,0);	//在Lu键树中删除键值

	pk=(pub_k *)SearchKey("my_k",4,key_no_lock);	//在Lu键树中查找键值
	if(!pk) printf("my_k 已销毁!\n");
	pd=(pub_d *)SearchKey("my_d",4,key_no_lock);	//在Lu键树中查找键值
	if(!pd) printf("my_d 已销毁!\n");

	LockKey(key_lock,Del_pub_d,OpLock_pub_d);	//在Lu键树中加锁键,只能存储pub_d类型

	pk=(pub_k *)malloc(sizeof(pub_k));
	pk->k=20;
	pd=(pub_d *)malloc(sizeof(pub_d));
	pd->d=5.67;
	InsertKey("my_k",4,key_lock,pk,Del_pub_k,NULL,1,&NowKey);//在Lu键树中注册pub_k类型键值,失败
	InsertKey("my_d",4,key_lock,pd,Del_pub_d,NULL,1,&NowKey);//在Lu键树中注册pub_d类型键值,成功

	pk=(pub_k *)SearchKey("my_k",4,key_lock);	//在Lu键树中查找键值,失败
	if(pk)
		printf("%d\n",pk->k);
	else
		printf("没有找到 my_k!\n");
	pd=(pub_d *)SearchKey("my_d",4,key_lock);	//在Lu键树中查找键值,成功
	if(pd) printf("%f\n",pd->d);

	DeleteKey("my_k",4,key_lock,NULL,0);		//在Lu键树中删除键值,失败
	DeleteKey("my_d",4,key_lock,NULL,0);		//在Lu键树中删除键值,成功

	pd=(pub_d *)SearchKey("my_d",4,key_lock);	//在Lu键树中查找键值
	if(!pd) printf("my_d 已销毁!\n");

	FreeLu();			//释放Lu
}

运行结果:

10
1.230000
my_k 已销毁!
my_d 已销毁!
没有找到 my_k!
5.670000
my_d 已销毁!

代码2:演示指针型私有键

#include <stdio.h>
#include <malloc.h>
#include "lu64.h"

#pragma comment( lib, "lu64.lib" )

typedef struct pri_k	//将注册为私有键
{
	int k;
} pri_k;
void _stdcall Del_pri_k(void *me)	//销毁pri_k的函数
{
	free(me);
}

LuData _stdcall OpLock_pri_k(luINT m,LuData *Para,void *hFor,int theOperator)	//pri_k的运算符重载函数
{
	LuData a;

	a.BType=luStaData_nil; a.VType=luStaData_nil; a.x=0;	//不对pri_k类型的对象做运算,总返回nil
	return a;
}

#define key_lock	(luPriKey_User-20)	//将对该私有键加锁
#define imax	10		//私有键值最大数

void main(void)
{
	pri_k *pk[imax],*p_k;
	int i;
	luKEY ByteNum;
	void *NowKey;		//返回已存在的键值

	if(!InitLu()) return;	//初始化Lu

	LockKey(key_lock,Del_pri_k,OpLock_pri_k);	//在Lu键树中加锁键,只能存储pri_k类型

	for(i=0;i<imax;i++)
	{
		pk[i]=(pri_k *)malloc(sizeof(pri_k));
		pk[i]->k=100+i;
		ByteNum= i%2 ? -1 : sizeof(luVOID);	//i为偶数时注册为指针键,否则注册为非指针键
		InsertKey((char *)&(pk[i]),ByteNum,key_lock,pk[i],Del_pri_k,NULL,1,&NowKey);	//在Lu键树中注册键值
	}

	printf("--- 保存在Lu键树中的数据!---\n\n");
	for(i=0;i<imax;i++)
	{
		p_k=(pri_k *)SearchKey((char *)&(pk[i]),sizeof(luVOID),key_lock);	//在Lu键树中查找键值
		if(p_k) printf("%d\n",p_k->k);
	}

	printf("\n--- 删除约1/3数据!---\n\n");
	for(i=0;i<imax/3;i++)
	{
		DeleteKey((char *)&(pk[i]),sizeof(luVOID),key_lock,Del_pri_k,0);	//在Lu键树中删除键值
	}

	for(i=0;i<imax;i++)
	{
		p_k=(pri_k *)SearchKey((char *)&(pk[i]),sizeof(luVOID),key_lock);	//在Lu键树中查找键值
		if(p_k)
			printf("%d\n",p_k->k);
		else
			printf("没有找到第 %d 个数据!\n",i);
	}

	printf("\n--- 运行垃圾收集器后数据!---\n\n");
	GC(0);	//垃圾收集

	for(i=0;i<imax;i++)
	{
		p_k=(pri_k *)SearchKey((char *)&(pk[i]),sizeof(luVOID),key_lock);	//在Lu键树中查找键值
		if(p_k)
			printf("%d\n",p_k->k);
		else
			printf("没有找到第 %d 个数据!\n",i);
	}

	printf("\n--- 解锁键并全部销毁数据!---\n\n");
	LockKey(key_lock,NULL,OpLock_pri_k);		//在Lu键树中解锁键

	for(i=0;i<imax;i++)
	{
		p_k=(pri_k *)SearchKey((char *)&(pk[i]),sizeof(luVOID),key_lock);	//在Lu键树中查找键值
		if(p_k)
			printf("%d\n",p_k->k);
		else
			printf("没有找到第 %d 个数据!\n",i);
	}

	FreeLu();		//释放Lu
}

运行结果:

--- 保存在Lu键树中的数据!---

100
101
102
103
104
105
106
107
108
109

--- 删除约1/3数据!---

没有找到第 0 个数据!
没有找到第 1 个数据!
没有找到第 2 个数据!
103
104
105
106
107
108
109

--- 运行垃圾收集器后数据!---

没有找到第 0 个数据!
没有找到第 1 个数据!
没有找到第 2 个数据!
没有找到第 3 个数据!
104
没有找到第 5 个数据!
106
没有找到第 7 个数据!
108
没有找到第 9 个数据!

--- 解锁键并全部销毁数据!---

没有找到第 0 个数据!
没有找到第 1 个数据!
没有找到第 2 个数据!
没有找到第 3 个数据!
没有找到第 4 个数据!
没有找到第 5 个数据!
没有找到第 6 个数据!
没有找到第 7 个数据!
没有找到第 8 个数据!
没有找到第 9 个数据!

代码3:演示非指针型私有键

    将代码2中的

#define key_lock (luPriKey_User-20) //将对该私有键加锁

    改为:

#define key_lock (luPoiKey_User-20) //将对该私有键加锁

    然后编译运行即可。

运行结果:

--- 保存在Lu键树中的数据!---

100
102
104
106
108

--- 删除约1/3数据!---

没有找到第 0 个数据!
没有找到第 1 个数据!
没有找到第 2 个数据!
没有找到第 3 个数据!
104
没有找到第 5 个数据!
106
没有找到第 7 个数据!
108
没有找到第 9 个数据!

--- 运行垃圾收集器后数据!---

没有找到第 0 个数据!
没有找到第 1 个数据!
没有找到第 2 个数据!
没有找到第 3 个数据!
104
没有找到第 5 个数据!
106
没有找到第 7 个数据!
108
没有找到第 9 个数据!

--- 解锁键并全部销毁数据!---

没有找到第 0 个数据!
没有找到第 1 个数据!
没有找到第 2 个数据!
没有找到第 3 个数据!
没有找到第 4 个数据!
没有找到第 5 个数据!
没有找到第 6 个数据!
没有找到第 7 个数据!
没有找到第 8 个数据!
没有找到第 9 个数据!

4 函数说明

    本例用到了Lu的7个输出函数:初始化Lu的函数InitLu,释放Lu的函数FreeLu,插入键值的函数InsertKey查找键值函数SearchKey,删除键值的函数DeleteKey,加锁键函数LockKey,垃圾收集器函数GC。从这里查看这些函数的说明:Lu编程指南

5 难点分析

    代码1演示了公有键的用法。(1)如果公有键没有加锁,可以存储若干种数据类型,如果进行了加锁,只能存储一种数据类型;(2)可以删除一个不存在的键而没有副作用;(3)删除键值时不需要提供删除函数,故谁都可以销毁公有键;(4)没有对InsertKeySearchKeyDeleteKeyLockKey的返回值做全面检查,但不影响演示效果。

    代码2演示了指针型私有键的用法。(1)程序先对私有键key_lock进行加锁,然后注册了10个对象,一半注册为指针键,一半注册为非指针键;(2)Lu脚本的垃圾收集器运行时,会回收指针键,但对非指针键没有影响;(3)键解锁时会自动销毁该类键型的所有数据。

    代码3演示了非指针型私有键的用法。(1)程序试图注册指针键,但失败了;(2)Lu脚本的垃圾收集器运行时,对非指针键没有影响。

    代码中在加锁一个键时,用到了运算符重载函数,在此先略过,以后会专门讨论该函数。

6 其他

    你可能注意到了,我的联系方式就在下面,如有不明之处或有什么建议,可随时与我进行联系。


版权所有© Lu程序设计 2002-2021,保留所有权利
E-mail: forcal@sina.com
  QQ:630715621
最近更新: 2021年05月23日