FcData32W.DLL V1.0(beta版) 用户指南
初级用户部分:在Forcal源程序中使用FcData 1 什么是FcData 2 FcData常量 3 FcData函数 4 类 5 在实数或复数表达式中使用FcData数据 6 FcData数据的自动初始化和销毁 7 效率 | 高级用户部分:在高级语言中使用FcData数据或利用高级语言扩展FcData的功能 8 FcData32W.dll中的输出函数 9 在其他模块中使用FcData数据 10 通过其他模块扩展FcData数据 |
正文:
FcData32W.dll是一个标准的Forcal扩展动态库,该库对Forcal的数据类型进行了扩展。
FcData中的所有数据都用一个指针进行标识,通过指针可以访问到FcData数据。Forcal的整数和实数是64位的,复数是128位的,在32位平台上,FcData指针是一个4字节整数,保存在整数、实数或复数的前4个字节中;在64位平台上,FcData指针是一个8字节整数,正好用一个整数、实数或复数的实部进行保存。FcData是通过Forcal整数表达式实现的。
FcData中的内置基本数据类型包括简单数据和数组,如下表所示:
数据类型 | 说明 | 单个数据字节数 | 取值范围 | 备注 |
int8 | 8位有符号整数 | 1 | -128~127 | |
Uint8,char | 8位无符号整数,ASCII字符 | 1 | 0~255 | ASCII字符、ANSI字符 |
int16 | 16位有符号整数 | 2 | -32768~32767 | |
Uint16 | 16位无符号整数 | 2 | 0~65535 | |
wchar | (宽)字符 | 2 | 0~65535 | Unicode字符,Forcal默认字符 |
int32 | 32位有符号整数 | 4 | -2147483648~2147483647 | |
Uint32 | 32位无符号整数 | 4 | 0~4294967295 | |
int64,int | 64位有符号整数 | 8 | -9223372036854775808~9223372036854775807 | |
Uint64,pointer | 64位无符号整数,指针 | 8 | 0~18446744073709551615 | 32位平台上,指针只用前4个字节 |
real32 | 单精度实数 | 4 | ±3.4E-38~±3.4E+38 | 占用整数或实数的前4个字节 |
real64,real | 双精度实数 | 8 | ±1.7E-308~±1.7E+308 | |
complex | 复数 | 16 | ±1.7E-308~±1.7E+308 | |
int8_s | 8位有符号整数数组 | 1 | -128~127 | |
Uint8_s,char_s | 8位无符号整数数组,字符数组 | 1 | 0~255 | ASCII字符串、ANSI字符串 |
int16_s | 16位有符号整数数组 | 2 | -32768~32767 | |
Uint16_s | 16位无符号整数数组 | 2 | 0~65535 | |
wchar_s,string | (宽)字符数组 | 2 | 0~65535 | Unicode字符串,Forcal默认字符串 |
int32_s | 32位有符号整数数组 | 4 | -2147483648~2147483647 | |
Uint32_s | 32位无符号整数数组 | 4 | 0~4294967295 | |
int64_s,int_s | 64位有符号整数数组 | 8 | -9223372036854775808~9223372036854775807 | |
Uint64_s,pointer_s | 64位无符号整数数组,指针数组 | 8 | 0~18446744073709551615 | 32位平台上,指针只用前4个字节 |
real32_s | 单精度实数数组 | 4 | ±3.4E-38~±3.4E+38 | 占用整数或实数的前4个字节 |
real64_s,real_s | 双精度实数数组 | 8 | ±1.7E-308~±1.7E+308 | |
complex_s | 复数数组 | 16 | ±1.7E-308~±1.7E+308 |
数组是具有相同的数据类型且拥有同一个指针标识的相关变量所组成的线性表,可以是一维或任意维数组。数组中的每个独立变量称作元素,每个元素即一个FcData简单数据。
除以上基本数据类型外,在FcData中还可用关键字“class”创建类,实现复杂的数据结构。
通过FcData32W.dll的输出函数接口,可以向FcData添加任意复杂的数据类型,这些类型称为外部基本数据类型。
使用二级函数typedef,可以对FcData基本数据类型进行扩展,称为扩展数据类型。实际上,任何一个FcData数据具有两个数据类型属性:扩展数据类型和基本数据类型。这两个类型属性均用4字节整数进行标识。FcData扩展数据类型可简称为FcData数据类型(以后如不加特别说明,FcData数据类型即指FcData扩展数据类型),用以表示各种不同类别的数据,而基本数据类型(包括内置的和外部的基本数据类型)较少,仅表示这种数据占多少个字节。
FcData中所有的数据都是用函数new()动态申请的(或者用函数newcopy()创建一个对象的副本),申请成功时返回一个数据指针,可通过该指针对数据进行操作,使用完后用函数delete()函数进行销毁,或者用函数DelAllFCD()一次性销毁所有数据。FcData中的数据是安全的,不存在内存泄漏,FcData中有自动回收垃圾的机制。
FcData中可以执行严格的或不严格的类型检查,这与具体的函数特性有关。如果函数检查FcData数据的扩展数据类型符合要求才进行操作,即是进行严格的数据检查;如果函数检查FcData数据的基本数据类型符合要求就进行操作,即是进行不严格的数据检查,具体请参考函数的相关说明。在执行严格的类型检查时,有一些函数可对不同类型的数据进行相互转换,提供了很多方便。
FcData中定义的直接对数据进行计算或操作的函数较少,FcData主要向Forcal提供更加丰富的数据类型,对FcData数据的计算或操作更多地依赖其他动态库的函数进行。
以下函数OutClass可以输出类的结构,本文中的例子将直接使用该函数,不再给出函数的实现。要演示这些例子,将该函数放到例子的前面和例子一起编译即可。
i:OutClass(pClass,n:len,i,j,str,BType,PArray,nPArray,pc)= //pClass是类指针,n是缓冲区大小,n太小时,有些基类将无法输出
{
printf{"/r/n/r/n***** 类简易分析程序 *****"},
PArray=new[pointer_s,n],nPArray=CDFSBase[pClass,PArray],
str="/[80]",
i=0,
(i<nPArray).while{
pc=PArray.get(i),len=FCDLen(pc),
printf{"/r/n/r/n类:{1,i}/r/n",pc},
j=0,
(j<len).while{
CGetNameI[pc,j,str,80],
printf{"/r/n类成员:{1,ns,-20}指针:{2,i,-12}删除属性:{3,i,-5}数据类别:",str,pc.CGetPI[j],pc.CGetAI[j]},
FCDType[pc.CGetPI[j],&BType],
which{
BType==int8, printf{"int8"},
BType==Uint8, printf{"Uint8,char"},
BType==int16, printf{"int16"},
BType==Uint16, printf{"Uint16"},
BType==wchar, printf{"wchar"},
BType==int32, printf{"int32"},
BType==Uint32, printf{"Uint32"},
BType==int64, printf{"int64,int"},
BType==Uint64, printf{"Uint64,pointer"},
BType==real32, printf{"real32"},
BType==real64, printf{"real64,real"},
BType==complex, printf{"complex"},
BType==int8_s, printf{"int8_s"},
BType==Uint8_s, printf{"Uint8_s,char_s"},
BType==int16_s, printf{"int16_s"},
BType==Uint16_s, printf{"Uint16_s"},
BType==wchar_s, printf{"wchar_s,string"},
BType==int32_s, printf{"int32_s"},
BType==Uint32_s, printf{"Uint32_s"},
BType==int64_s, printf{"int64_s,int_s"},
BType==Uint64_s, printf{"Uint64_s,pointer_s"},
BType==real32_s, printf{"real32_s"},
BType==real64_s, printf{"real64_s,real_s"},
BType==complex_s,printf{"complex_s"},
BType==class, printf{"class,基类"},
BType==0, printf{"非FcData数据"},
printf{"外部数据类型"}
},
j++
},
i++
},
printf{"/r/n/r/n"},
if{nPArray==n,printf{"警告:指定的缓冲区太小,可能有些基类无法搜索到。/r/n/r/n"}},
printf{"***** 类分析结束 *****/r/n/r/n"},
delete[PArray]
};
FcData中定义的整数和实数常量如下表:
常 量 | 说 明 | 常 量 | 说 明 | |
int8 | 定义8位有符号整数 | class | 创建类对象 | |
Uint8,char | 定义8位无符号整数,定义ASCII字符 | EndType | 数据定义结束标志 | |
int16 | 定义16位有符号整数 | NotDelete | 删除类对象时,不删除指定的类成员 | |
Uint16 | 定义16位无符号整数 | NULL | NULL = 0 | |
wchar | 定义(宽)字符 | true | 逻辑真,true != 0 | |
int32 | 定义32位有符号整数 | false | 逻辑假,false = 0 | |
Uint32 | 定义32位无符号整数 | |||
int64,int | 定义64位有符号整数 | |||
Uint64,pointer | 定义64位无符号整数,定义指针 | |||
real32 | 定义单精度实数 | |||
real64,real | 定义双精度实数 | |||
complex | 定义复数 | |||
int8_s | 定义8位有符号整数数组 | |||
Uint8_s,char_s | 定义8位无符号整数数组,定义ASCII字符数组 | |||
int16_s | 定义16位有符号整数数组 | |||
Uint16_s | 定义16位无符号整数数组 | |||
wchar_s,string | 定义(宽)字符数组 | |||
int32_s | 定义32位有符号整数数组 | |||
Uint32_s | 定义32位无符号整数数组 | |||
int64_s,int_s | 定义64位有符号整数数组 | |||
Uint64_s,pointer_s | 定义64位无符号整数数组,定义指针数组 | |||
real32_s | 定义单精度实数数组 | |||
real64_s,real_s | 定义双精度实数数组 | |||
complex_s | 定义复数数组 |
命名约定:如果函数的参数中有源操作数和目的操作数,当函数名中有“to”时,源操作数在前,目的操作数在后;当函数名中没有“to”时,目的操作数在前,源操作数在后。
字符串约定:函数中涉及的字符串,若未加说明,均为Unicode字符串。
函 数 | 类型 | 用 途 | 函 数 | 类型 | 用 途 | |
new | 整数函数、实数函数 | 申请FcData数据 | CSetLen | 整数函数 | 设置类的大小 | |
newcopy | 整数函数、实数函数 | 创建FcData数据的副本 | CHasName | 整数函数 | 根据类成员名称测试类成员是否存在 | |
delete | 整数函数、实数函数、复数函数 | 销毁FcData数据 | CDupName | 整数函数 | 根据类成员名称测试类成员是否重名 | |
DelAllFCD | 整数函数 | 销毁所有FcData数据 | CSetAllAttr | 整数函数 | 设置所有类成员的属性 | |
DelAllFCDNum | 整数函数 | 得到销毁所有FcData数据的次数 | CSD | 整数函数 | 得到基类成员指针,深度优先 | |
NowFCDNum | 整数函数 | 返回当前FcData数据的数目 | CSB | 整数函数 | 得到基类成员指针,广度优先 | |
SetFCDMax | 整数函数 | 设置允许申请的FcData数据的最大数 | CSetItem | 整数函数 | 根据类成员名称设置类的成员 | |
SetFCDRecurMax | 整数函数 | 设置CSD、CSB、copy等函数操作的类层次深度最大值 | CSetItemI | 整数函数 | 根据类成员地址设置类的成员 | |
typedef | 整数函数 | 定义扩展数据类型 | CGetNameI | 整数函数 | 根据类成员地址获得类成员的名称 | |
FCDType | 整数函数 | 得到FcData数据的类型 | CSetName | 整数函数 | 根据类成员名称设置类成员名称 | |
FCDLen | 整数函数 | 得到FcData(数组)数据长度、维数 | CSetNameI | 整数函数 | 根据类成员地址设置类成员名称 | |
copy | 整数函数、实数函数 | 复制FcData数据 | CGetP | 整数函数 | 根据类成员名称获得类成员指针 | |
get | 整数函数、实数函数 | 得到一个FcData数据的值 | CGetPI | 整数函数 | 根据类成员地址获得类成员指针 | |
set | 整数函数、实数函数 | 设置一个FcData数据的值 | CSetP | 整数函数 | 根据类成员名称设置类成员指针 | |
FCDToStr | 整数函数 | 将FcData数据转换为字符串 | CSetPI | 整数函数 | 根据类成员地址设置类成员指针 | |
StrToFCD | 整数函数 | 将字符串转换为FcData数据 | CGetA | 整数函数 | 根据类成员名称获得类成员属性 | |
FCDstrlen | 整数函数 | 得到字符串长度 | CGetAI | 整数函数 | 根据类成员地址获得类成员属性 | |
FCDstrcpy | 整数函数 | 复制字符串 | CSetA | 整数函数 | 根据类成员名称设置类成员属性 | |
FCDstrcat | 整数函数 | 连接字符串 | CSetAI | 整数函数 | 根据类成员地址设置类成员属性 | |
FCDstrcmp | 整数函数 | 比较字符串 | CAdd | 整数函数 | 类相加 | |
associated(p) | 整数函数、实数函数、复数函数 | 判断指针p是否有效,有效时返回非0值(逻辑真),否则返回0 | CAppend | 整数函数 | 在类的末尾追加成员 | |
null(&p) | 整数函数、实数函数、复数函数 | 使指针p无效,返回一个无效指针 | CInsert | 整数函数 | 根据类成员名称在类中插入成员 | |
ftod(&n) | 整数函数 | 将单精度实数n转换为双精度实数,返回转换后的值 | CInsertI | 整数函数 | 根据类成员地址在类中插入成员 | |
dtof(&n) | 整数函数 | 将双精度实数n转换为单精度实数,返回转换后的值,可能丢失精度 | CPop | 整数函数 | 返回类的最后一个成员,类长度减1 | |
printf | 整数函数、实数函数 | 格式化输出函数,输出到标准设备 | CDelete(p,"name") | 整数函数 | 根据类成员名称删除类p的成员"name" | |
printfs | 整数函数、实数函数 | 格式化输出函数,输出到字符串 | CDeleteI(p,i) | 整数函数 | 根据类成员地址删除类p的第i个成员 | |
CReverse(p) | 整数函数 | 类p中所有成员反序 | ||||
CSwap(p,i,j) | 整数函数 | 交换类p的成员i和j的位置 | ||||
CSort | 整数函数 | 类成员排序 | ||||
CDFSBase | 整数函数 | 深度搜索类的基类 |
[返回本类函数列表] [返回页首] new(Type:n1,n2,...,nm,EndType:x0,x1,x2,...):申请FcData数据
Type:FcData数据类型。
n1,n2,...,nm:如果Type是数组类型,该项说明申请的是m维数组,共存储n1×n2×...×nm个数据。n1,n2,...,nm这m个参数中的每一个都必须是大于0的数。数组的下标从0开始,例如第i维参数为ni,则ni的取值范围为[0,1,2,...,ni-1]。m维数组的第一个元素下标为[0,0,...,0],最后一个元素下标为[n1-1,n2-1,...,nm-1]。数组元素按最低存储地址到最高存储地址顺序存放。如果申请的不是数组类型,该项参数缺省。
EndType:如果申请的是数组类型,该项为数组维数结束标志,否则缺省;如果申请的类,该项为类大小结束标志,否则缺省。
x0,x1,x2,...:初始化参数。如果是数组类型,参数按最低存储地址到最高存储地址顺序存放,多余的参数将被忽略。wchar和wchar_s(string)类型参数用字符串"abc..."赋初值。如果将一个多字节数(例如大整数)赋给一个少字节数(例如小整数),数据将被截断。如果一个Type类型数据大于8个字节(例如复数),则每个数据占用多个参数,即连续的多个参数组合为一个Type类型数据,占用参数的个数,取决于一个Type类型数据的长度。
说明:FcData中所有的数据都用函数new()动态申请。申请成功返回一个指向数据的指针,可通过该指针操作参数;申请失败返回0。
通过整数函数new()可以申请的数据类型及举例见下表。
Type | 申请的数据 | 简单例子 | 简单例子说明 | 赋初值的例子 | 赋初值的例子说明 |
int8 | 8位有符号整数 | new(int8) | 申请一个8位有符号整数。 | new(int8,2) | 申请一个8位有符号整数并赋初值为2。 |
Uint8,char | 8位无符号整数,ASCII字符 | new(Uint8) | 申请一个8位无符号整数。 | new(char,66) | 申请一个8位无符号整数(ASCII字符)并赋初值为66,66为该字符的ASCII代码。 |
int16 | 16位有符号整数 | new(int16) | 申请一个16位有符号整数。 | new(int16,166) | 申请一个16位有符号整数并赋初值为166。 |
Uint16 | 16位无符号整数 | new(Uint16) | 申请一个16位无符号整数。 | new(Uint16,166) | 申请一个16位无符号整数并赋初值为166。 |
wchar | 宽字符 | new(wchar) | 申请一个宽字符 | new(wchar,"a") | 申请一个宽字符并赋初值为"a",该字符为Unicode字符。 |
int32 | 32位有符号整数 | new(int32) | 申请一个32位有符号整数。 | new(int32,166888) | 申请一个32位有符号整数并赋初值为166888。 |
Uint32 | 32位无符号整数 | new(Uint32) | 申请一个32位无符号整数。 | new(Uint32,166888) | 申请一个32位无符号整数并赋初值为166888。 |
int64,int | 64位有符号整数 | new(int64) | 申请一个64位有符号整数。 | new(int64,166888888888) | 申请一个64位有符号整数并赋初值为(166888888888)。 |
Uint64 | 64位无符号整数,指针 | new(Uint64) | 申请一个64位无符号整数。 | new(Uint64,166888888888) | 申请一个64位无符号整数并赋初值为(166888888888)。 |
real32 | 单精度实数 | new(real32) | 申请一个单精度实数。 | new(real32,166888) | 申请一个单精度实数并赋初值为166888,该数要按单精度实数规则进行解释,只取数的前4个字节进行解释。 |
real64,real | 双精度实数 | new(real64) | 申请一个双精度实数。 | new(real64,166888) | 申请一个双精度实数并赋初值为(166888),按双精度实数规则进行解释。 |
complex | 复数 | new(complex) | 申请一个复数。 | new(complex,16,68) | 申请一个复数并赋初值为(16,68),这2个数共16个字节,按复数规则进行解释:第一个参数为复数的实部,第二个参数为复数的虚部。 |
int8_s | 8位有符号整数数组 | new(int8_s,5) | 申请一个一维8位有符号整数数组,长度为5。EndType为数据定义结束标志,下同。 | new(int8_s,EndType,66,67,68) | 申请一个一维8位有符号整数数组并赋初值为(66,67,68),长度为初值数目。 |
new(int8_s,5,EndType) | new(int8_s,5,EndType,66,67,68) | 申请一个一维8位有符号整数数组并赋初值为(66,67,68),长度为5。 | |||
new(int8_s,2,3) | 申请一个二维8位有符号整数数组,长度为6。 | new(int8_s,2,3,EndType,66,67,68) | 申请一个二维8位有符号整数数组并赋初值为(66,67,68),长度为6。 | ||
new(int8_s,2,3,EndType) | |||||
Uint8_s,char_s | 8位无符号整数数组,ASCII字符数组 | new(Uint8_s,5) | 申请一个一维8位无符号整数数组,长度为5。 | new(Uint8_s,EndType,66,67,68) | 申请一个一维8位无符号整数数组并赋初值为(66,67,68),长度为初值数目。 |
new(Uint8_s,5,EndType) | new(Uint8_s,5,EndType,66,67,68) | 申请一个一维8位无符号整数数组并赋初值为(66,67,68),长度为5。 | |||
new(Uint8_s,2,3,5) | 申请一个三维8位无符号整数数组,长度为30。 | new(Uint8_s,2,3,5,EndType,66,67,68,69,70) | 申请一个三维8位无符号整数数组并赋初值为(66,67,68,69,70),长度为30。 | ||
new(Uint8_s,2,3,5,EndType) | |||||
int16_s | 16位有符号整数数组 | new(int16_s,5) | 申请一个一维16位有符号整数数组,长度为5。 | new(int16_s,EndType,66,67,68) | 申请一个一维16位有符号整数数组并赋初值为(66,67,68),长度为初值数目。 |
new(int16_s,5,EndType) | new(int16_s,5,EndType,66,67,68) | 申请一个一维16位有符号整数数组并赋初值为(66,67,68),长度为5。 | |||
new(int16_s,2,3,5,2) | 申请一个四维16位有符号整数数组,长度为60。 | new(int16_s,2,3,5,2,EndType,66,67,68,69,70) | 申请一个四维16位有符号整数数组并赋初值为(66,67,68,69,70),长度为60。 | ||
new(int16_s,2,3,5,2,EndType) | |||||
Uint16_s | 16位无符号整数数组 | new(Uint16_s,5) | 申请一个一维16位无符号整数数组,长度为5。 | new(Uint16_s,EndType,66,67,68) | 申请一个一维16位无符号整数数组并赋初值为(66,67,68),长度为初值数目。 |
new(Uint16_s,5,EndType) | new(Uint16_s,5,EndType,66,67,68) | 申请一个一维16位无符号整数数组并赋初值为(66,67,68),长度为5。 | |||
new(Uint16_s,2,3,5) | 申请一个三维16位无符号整数数组,长度为30。 | new(Uint16_s,2,3,5,EndType,66,67,68,69,70) | 申请一个三维16位无符号整数数组并赋初值为(66,67,68,69,70),长度为30。 | ||
new(Uint16_s,2,3,5,EndType) | |||||
wchar_s,string | 宽字符数组 | new(wchar_s,5) | 申请一个一维宽字符数组,长度为5。 | new(wchar_s,EndType,"abc") | 申请一个一维宽字符数组并赋初值为"abc",长度为字符串长度,在这个例子中,长度为4(最后一位为字符串结束符标志0)。 |
new(wchar_s,5,EndType) | new(wchar_s,5,EndType,"abc") | 申请一个一维宽字符数组并赋初值为"abc",长度为5。 | |||
new(wchar_s,2,3) | 申请一个二维宽字符数组,长度为6。 | new(wchar_s,2,3,EndType,"abc") | 申请一个二维宽字符数组并赋初值为"abc",长度为6。 | ||
new(wchar_s,2,3,EndType) | |||||
int32_s | 32位有符号整数数组 | new(int32_s,5) | 申请一个一维32位有符号整数数组,长度为5。 | new(int32_s,EndType,66,67,68) | 申请一个一维32位有符号整数数组并赋初值为(66,67,68),长度为初值数目。 |
new(int32_s,5,EndType) | new(int32_s,5,EndType,66,67,68) | 申请一个一维32位有符号整数数组并赋初值为(66,67,68),长度为5。 | |||
new(int32_s,2,3,5) | 申请一个三维32位有符号整数数组,长度为30。 | new(int32_s,2,3,5,EndType,66,67,68,69,70) | 申请一个三维32位有符号整数数组并赋初值为(66,67,68,69,70),长度为30。 | ||
new(int32_s,2,3,5,EndType) | |||||
Uint32_s | 32位无符号整数数组 | new(Uint32_s,5) | 申请一个一维32位无符号整数数组,长度为5。 | new(Uint32_s,EndType,66,67,68) | 申请一个一维32位无符号整数数组并赋初值为(66,67,68),长度为初值数目。 |
new(Uint32_s,5,EndType) | new(Uint32_s,5,EndType,66,67,68) | 申请一个一维32位无符号整数数组并赋初值为(66,67,68),长度为5。 | |||
new(Uint32_s,2,3,5) | 申请一个三维32位无符号整数数组,长度为30。 | new(Uint32_s,2,3,5,EndType,66,67,68,69,70) | 申请一个三维32位无符号整数数组并赋初值为(66,67,68,69,70),长度为30。 | ||
new(Uint32_s,2,3,5,EndType) | |||||
int64_s,int_s | 64位有符号整数数组 | new(int64_s,5) | 申请一个一维64位有符号整数数组,长度为5。 | new(int64_s,EndType,66,67,68,69) | 申请一个一维64位有符号整数数组并赋初值为(66,67,68,69),长度为初值数目。 |
new(int64_s,5,EndType) | new(int64_s,5,EndType,66,67,68,69) | 申请一个一维64位有符号整数数组并赋初值为(66,67,68,69),长度为5。 | |||
new(int64_s,2,3,5) | 申请一个三维64位有符号整数数组,长度为30。 | new(int64_s,2,3,5,EndType,66,67,68,69,70,71) | 申请一个三维64位有符号整数数组并赋初值为(66,67,68,69,70,71),长度为30。 | ||
new(int64_s,2,3,5,EndType) | |||||
Uint64_s | 64位无符号整数数组,指针数组 | new(Uint64_s,5) | 申请一个一维64位无符号整数数组,长度为5。 | new(Uint64_s,EndType,66,67,68,69) | 申请一个一维64位无符号整数数组并赋初值为(66,67,68,69),长度为初值数目。 |
new(Uint64_s,5,EndType) | new(Uint64_s,5,EndType,66,67,68,69) | 申请一个一维64位无符号整数数组并赋初值为(66,67,68,69),长度为5。 | |||
new(Uint64_s,2,3,5) | 申请一个三维64位无符号整数数组,长度为30。 | new(Uint64_s,2,3,5,EndType,66,67,68,69,70,71) | 申请一个三维64位无符号整数数组并赋初值为(66,67,68,69,70,71),长度为30。 | ||
new(Uint64_s,2,3,5,EndType) | |||||
real32_s | 单精度实数数组 | new(real32_s,5) | 申请一个一维单精度实数数组,长度为5。 | new(real32_s,EndType,66,67,68,69) | 申请一个一维单精度实数数组并赋初值为(66,67,68,69),长度为初值数目,所有数值按单精度实数规则进行解释,只取数的前4个字节进行解释。 |
new(real32_s,5,EndType) | new(real32_s,5,EndType,66,67,68,69) | 申请一个一维单精度实数数组并赋初值为(66,67,68,69),长度为5,所有数值按单精度实数规则进行解释。 | |||
new(real32_s,2,3,5) | 申请一个三维单精度实数数组,长度为30。 | new(real32_s,2,3,5,EndType,66,67,68,69,70,71) | 申请一个三维单精度实数数组并赋初值为(66,67,68,69,70,71),长度为30,所有数值按单精度实数规则进行解释。 | ||
new(real32_s,2,3,5,EndType) | |||||
real64_s,real_s | 双精度实数数组 | new(real64_s,5) | 申请一个一维双精度实数数组,长度为5。 | new(real64_s,EndType,66,67,68,69,70,71,72,73) | 申请一个一维双精度实数数组并赋初值为(66,67,68,69,70,71,72,73),长度为初值数目。 |
new(real64_s,5,EndType) | new(real64_s,5,EndType,66,67,68,69,70,71,72,73) | 申请一个一维双精度实数数组并赋初值为(66,67,68,69,70,71,72,73),长度为5。 | |||
new(real64_s,2,3,5) | 申请一个三维双精度实数数组,长度为30。 | new(real64_s,2,3,5,EndType,66,67,68,69,70,71,72,73) | 申请一个三维双精度实数数组并赋初值为(66,67,68,69,70,71,72,73),长度为30。 | ||
new(real64_s,2,3,5,EndType) | |||||
complex_s | 复数数组 | new(complex_s,5) | 申请一个一维复数数组,长度为5。 | new(complex_s,EndType,66,67,68,69,70,71,72,73) | 申请一个一维复数数组并赋初值为(66,67,68,69,70,71,72,73),长度为初值数目/2 ,所有数值按复数规则进行解释,此例中有4个复数。 |
new(complex_s,5,EndType) | new(complex_s,5,EndType,66,67,68,69,70,71,72,73) | 申请一个一维复数数组并赋初值为(66,67,68,69,70,71,72,73),长度为5,所有数值按复数规则进行解释。 | |||
new(complex_s,2,3,5) | 申请一个三维复数数组,长度为30。 | new(complex_s,2,3,5,EndType,66,67,68,69,70,71,72,73) | 申请一个三维复数数组并赋初值为(66,67,68,69,70,71,72,73),长度为30,所有数值按复数规则进行解释 | ||
new(complex_s,2,3,5,EndType) | |||||
class | 类 | new{class,5} | 申请一个类,有5个类成员(类缓冲区可存放5个类成员)。类的详细说明请参考“类”。 | new(class,EndType,"a","b",NULL,"999",NULL) | 申请一个类,有5个类成员(类缓冲区可存放5个类成员),其中三个有名字的成员"a","b"和"999"。类成员的类型在申请类对象并进行赋值时确定,类成员的类型可以是一个类对象 。类的详细说明请参考“类”。 |
new{class,5,EndType} | new(class,5,EndType,"a","b",NULL,"999") | ||||
new{class,5,8} | 申请一个类,有5个类成员(类缓冲区可存放8个类成员)。类的详细说明请参考“类”。 | new(class,5,8,"a","b","999") | 申请一个类,有5个类成员(类缓冲区可存放8个类成员),其中前三个为"a","b"和"999"。类成员的类型在申请类对象并进行赋值时确定,类成员的类型可以是一个类对象 。类的详细说明请参考“类”。 | ||
new{class,5,8,EndType} | new(class,5,8,EndType,"a","b","999") | ||||
其他类型OtherType | 其他模块向FcData注册的数据类型 | new(OtherType) | 申请一个其他模块向FcData注册的数据,数据类型为OtherType。OtherType由其他模块定义。 |
[例子]
实数函数new()仅简单地调用了整数函数new(),因而二者的功能完全相同,但在实数表达式中使用函数new()时,其参数要根据实际情况进行必要的转换。
[例子]
(:x)= x=new[rtoi(real_s),rtoi(5),rtoi(EndType),11.11,22.22,33.33],printf{"{1,r}/r/n",get[x,rtoi(2)]},delete[x];
[返回本类函数列表] [返回页首] newcopy(pData,subBegin,subEnd):创建FcData数据的副本
pData:FcData数据指针。
subBegin:如果pFcData是一个类。subBegin和subEnd指出类成员序号的位置,subBegin≤subEnd。newcopy函数将以subBegin和subEnd之间的部分类成员创建一个类的副本。该参数可以缺省。
subEnd:该参数可以缺省。如果subBegin没有缺省,subEnd默认为类pFcData的最后一个成员。
说明:newcopy(p)将创建p的副本,p可以是一个复杂的类;newcopy(p,3)将创建一个新类,其类的成员是类p中自序号3的成员开始的后续所有成员的副本;newcopy(p,3,5)将创建一个新类,其类的成员是类p中3~5号成员的副本。如果类成员属性为false,将不产生类成员的副本,新的类成员与原类成员指向同一个地址。
[例子1]
以下类的继承实现了如下类层次关系,可看作一棵树。
"c":a-->"a":11
|
"e":cd-->|
| |
| "d":44
ef-->|
| "a":22
| |
"f":ab-->|
|
"b":33
i::A() = new[class,EndType:"a"]; //类定义,有一个类成员
i::AB() = new[class,EndType:"a","b"]; //类定义,有两个类成员
i::CD() = new[class,EndType:"c","d"]; //类定义,有两个类成员
i::EF() = new[class,EndType:"e","f"]; //类定义,有两个类成员
i:g(::a,ab,cd,ef) =
{ a=A().CSetItem{"a":new(int,11)}, //申请A类型的类对象并赋初值
ab=AB().CSetItem{"a":new(int,22),"b":new(int,33)},//申请AB类型的类对象并赋初值
cd=CD().CSetItem{"c":a,"d":new(int,44)}, //申请CD类型的类对象并赋初值
ef=EF().CSetItem{"e":cd,"f":ab} //申请EF类型的类对象并赋初值
};
i:h(::ef) = ef.OutClass[10]; //输出类ef的结构
i:i(::ef,ef1) = ef1=newcopy(ef),ef1.OutClass[10]; //创建类ef的副本,并输出其结构
i:j(::ef,ef2) = ef2=newcopy(ef,0,0),ef2.OutClass[10];//创建类ef的第0号成员的副本,并输出其结构
i:k(::ef,ef3) = ef3=newcopy(ef,1,1),ef3.OutClass[10];//创建类ef的第1号成员的副本,并输出其结构
i:l(::ef,ef4) = ef4=newcopy(ef,0,1),ef4.OutClass[10];//创建类ef的第1~2号成员的副本,并输出其结构
i:m(::ef,ef5) = ef5=newcopy(ef,0),ef5.OutClass[10]; //创建类ef的从0号成员开始的所有成员的副本,并输出其结构
i:n(::ef,ef6) = ef6=newcopy(ef,1),ef6.OutClass[10]; //创建类ef的从1号成员开始的所有成员的副本,并输出其结构
i:o(::ef,ef1,ef2,ef3,ef4,ef5,ef6) = delete[ef],delete[ef1],delete[ef2],delete[ef3],delete[ef4],delete[ef5],delete[ef6]; //删除类对象
[例子2]
以下类的继承实现了如下类层次关系,是个循环类,可看作一张连通图。
"c":a-->"a":11
|
"e":cd-->|
| |
| "d":44
ef-->|
| "a":ef
| |
"f":ab-->|
|
"b":33
i::A() = new[class,EndType:"a"]; //类定义,有一个类成员
i::AB() = new[class,EndType:"a","b"]; //类定义,有两个类成员
i::CD() = new[class,EndType:"c","d"]; //类定义,有两个类成员
i::EF() = new[class,EndType:"e","f"]; //类定义,有两个类成员
i:g(::a,ab,cd,ef) =
{ a=A().CSetItem{"a":new(int,11)}, //申请A类型的类对象并赋初值
ab=AB().CSetItem{"b":new(int,33)}, //申请AB类型的类对象并赋初值
cd=CD().CSetItem{"c":a,"d":new(int,44)}, //申请CD类型的类对象并赋初值
ef=EF().CSetItem{"e":cd,"f":ab}, //申请EF类型的类对象并赋初值
ab.CSetItem{"a":ef} //构成循环类
};
i:h(::ef) = ef.OutClass[10]; //输出类ef的结构
i:i(::ef,ef1) = ef1=newcopy(ef),ef1.OutClass[10]; //创建类ef的副本,并输出其结构
i:j(::ef,ef2) = ef2=newcopy(ef,0,0),ef2.OutClass[10];//创建类ef的第0号成员的副本,并输出其结构
i:k(::ef,ef3) = ef3=newcopy(ef,1,1),ef3.OutClass[10];//创建类ef的第1号成员的副本,并输出其结构
i:l(::ef,ef4) = ef4=newcopy(ef,0,1),ef4.OutClass[10];//创建类ef的第1~2号成员的副本,并输出其结构
i:m(::ef,ef5) = ef5=newcopy(ef,0),ef5.OutClass[10]; //创建类ef的从0号成员开始的所有成员的副本,并输出其结构
i:n(::ef,ef6) = ef6=newcopy(ef,1),ef6.OutClass[10]; //创建类ef的从1号成员开始的所有成员的副本,并输出其结构
i:o(::ef,ef1,ef2,ef3,ef4,ef5,ef6) = delete[ef],delete[ef1],delete[ef2],delete[ef3],delete[ef4],delete[ef5],delete[ef6]; //删除类对象
[返回本类函数列表] [返回页首] delete(pData):销毁FcData数据
pData:FcData数据指针。
说明:FcData数据用完后应及时用该函数销毁,释放数据所占据的空间。可在任意表达式中使用该函数。
[例子]
[返回本类函数列表] [返回页首] DelAllFCD():销毁所有FcData数据
[返回本类函数列表] [返回页首] DelAllFCDNum():获得销毁所有FcData数据的次数
说明:比较在不同时刻执行该函数的返回值,可确定是否销毁了所有的FcData数据。若两次执行的返回值相等,没有销毁所有的FcData数据,若不相等,销毁了所有的FcData数据。
[返回本类函数列表] [返回页首] NowFCDNum(n):返回当前FcData数据的数目
n:显示当前有效的FcData数据指针的最大数目。
说明:该函数可用来检查有哪些数据没有及时释放。
[返回本类函数列表] [返回页首] SetFCDMax(n):设置允许申请的FcData数据的最大数
说明:缺省的FcData数据个数最大值为10000。该函数避免了在无限循环中申请数据导致的内存耗损。
FcData内部有一个计数器,每当用函数new()申请一个FcData数据,计数器就增1,但用函数delete()销毁数据时,计数器并不减1,这样当计数器达到设定的最大值时,就不能再申请数据了。不过,调用函数NowFCDNum()可以使计数器的计数准确,只要及时用函数delete()销毁了不用的数据,就可以不断地用函数new()申请新数据。由于函数NowFCDNum()运行较慢,一般仅在程序的开头或结尾执行一次。
[返回本类函数列表] [返回页首] SetFCDRecurMax(n):设置CSD、CSB、copy、newcopy、CDFSBase等函数操作的类层次深度最大值
n:设置CSD、CSB、copy等函数操作的类层次深度最大值,n>=100,否则保持原先的设置不变。
说明:函数返回实际的CSD、CSB、copy等函数操作的类层次深度最大值。
警告:当n过大时,使用CSD、CSB、copy、newcopy、CDFSBase等函数时可能导致系统堆栈溢出。
[返回本类函数列表] [返回页首] typedef(bNew,OldType):定义或删除扩展数据类型
bNew:bNew为逻辑真时定义一个扩展数据类型,函数返回新的数据类型标识;bNew为逻辑假时删除一个扩展数据类型。
OldType:已存在的FcData数据类型标识。
说明:函数返回0时操作失败。删除一个扩展数据类型对已申请的该类型数据无影响,但不能再使用该数据类型申请新的数据。
通常将定义的数据类型用一个符号常量进行标识,以后在申请数据时可以使用该符号常量。如下例:
i:const["type_char",typedef(true,char)]; //将定义的数据类型保存在永久性常量type_char中
编译运行以上表达式,然后输入下例代码并执行:
i:type_char;
i:new(type_char);
[返回本类函数列表] [返回页首] FCDType(pData,&BasicType):得到FcData数据的类型
pData:FcData数据指针。
BasicType:返回FcData基本数据类型。
[返回本类函数列表] [返回页首] FCDLen(pFCD,&nArray,&n1,&n2,... ...):得到FcData(数组)数据长度、维数
pFCD:FcData数据指针。
nArray:如果pFCD是数组,该参数返回数组的维数;如果pFCD是类,该参数返回类缓冲区的大小。该参数可以缺省。
n1,n2,... ...:如果pFCD是数组,这些参数返回数组的各维数大小。如果参数不够用,则返回的数组维数不完整。这些参数可以缺省。
返回值:如果pFCD是简单数据返回0;如果pFCD是数组数据返回数组长度;如果pFCD是类返回类成员的数目;其他情况返回-1。
[例子1]
i: OutVector(p:k,i)= k=FCDLen(p),printf{"/r/n"},i=0,(i<k).while{printf{"{1,r,14.6}",get[p,i]},i++},printf{"/r/n"}; //输出一维数组
(:x)= x=new[rtoi(real_s),rtoi(5),rtoi(EndType),11.11,22.22,33.33],OutVector[x],delete[x];
[例子2]
i: OutMatrix(p:n1,n2,k,i,j)= //输出二维数组(矩阵)
{
FCDLen(p,&k,&n1,&n2),
if[k!=2,printf{"/r/n*** 地址为{1,i}的对象不是一个矩阵! ***/r/n",p.ptoi()},return(0)],
i=0,(i<n1).while{
printf{"/r/n"},
j=0,(j<n2).while{printf{"{1,r,14.6}",get[p,i,j]},j++},
i++
},
printf{"/r/n"}
};
(:x)= x=new[rtoi(real_s),rtoi(3),rtoi(3),rtoi(EndType),11.11,22.22,33.33],OutMatrix[x],delete[x];
[返回本类函数列表] [返回页首] copy(dest,source,bSame):复制FcData数据
dest:FcData目的数据指针。
source:FcData源数据指针。
bSame:当bSame=true时,dest和source的数据类型完全相同才进行复制;当bSame=false时,dest和source的类型不必完全相同,只要数据元素的字节数相同就可进行复制。若缺省该参数,相当于bSame=true。
说明:将源数据复制到目的数据。如果进行类对象的复制,要求类对象有相同的数据结构,但bSame=false时,类成员不必严格匹配。
注意:该函数所能操作的类层次深度受函数SetFCDRecurMax的设定值的影响,不能在一个类层次特别多的类(例如:比较长的链表,类层次有上万层)中使用该函数。
[例子1] i:(:a,b)= a=new[string,80,EndType:"hello FcData!"],b=new[string,80],copy[b,a],"{1,s}/r/n".b.printf[];
[例子2] i:(:a,b)= a=new[int16,-823],b=new[Uint16],copy[b,a,false],b.get[];
[例子3] 简单的类对象复制
i:a(::a,b) = a=new[class,EndType,"a","b"], b=new[class,EndType,"a","b"]; //申请类a、b,有两个类成员 i:b(::a,b) = a.CSetItem{"a",new[int,89]:"b",new[string,80,EndType,"hello FcData!"]}, //给类a的成员赋值 b.CSetItem{"a",new[int]:"b",new[string,80]}; //申请类b的成员,但没有赋值 i:c(::a,b) = copy[b,a]; //复制类对象 i:d(::b) = b."a".get[]; //获得类对象b的类成员"a"的值 i:e(::b) = printf["{1,s}/r/n",(b."b".CGetP())]; //获得类对象b的类成员"b"的值
[例子4] 复杂的类对象复制
i::Ca() = new[class,EndType,"a"]; //定义申请类的函数Ca,有一个类成员 i::Cabc() = new[class,EndType,"a","b","c"]; //定义申请类的函数Cabc,有三个类成员 i:c(::a,b) = a=Cabc().CSetItem{ //申请Cabc类型的类对象并给类成员赋初值,嵌套了类Ca "a",new[int,89], "b",new[string,80,EndType,"hello FcData!"], "c",Ca().CSetItem{ "a",new[int,-789] } }, b=Cabc().CSetItem{ //申请Cabc类型的类对象,但类成员没有赋初值,嵌套了类Ca "a",new[int], "b",new[string,80], "c",Ca().CSetItem{ "a",new[int] } }; i:d(::a,b) = copy[b,a]; //复制类对象 i:e(::b) = b."a".get[]; //获得类对象b的类成员"a"的值 i:f(::b) = printf["{1,s}/r/n",(b."b".CGetP())]; //获得类对象b的类成员"b"的值 i:g(::b) = b."c"."a".get[]; //获得类对象b的基类成员"c"的类成员"a"的值
实数函数copy()调用整数函数copy()进行对象复制,但二者的功能与用法完全相同。
[例子]
(:x,y)= x=new[rtoi(real_s),rtoi(5),rtoi(EndType),11.11,22.22,33.33],
y=new[rtoi(real_s),rtoi(5)],
copy[y,x],
printf{"{1,r}/r/n",get[y,rtoi(2)]},
delete[x],delete[y];
[返回本类函数列表] [返回页首] get(pData:"a","b",...,"x":n1,n2,...,nm:&x0,&x1,&x2,...):得到一个FcData数据的值
pData:FcData数据指针。
"a","b",...,"x":如果pData是类对象,该项指出了pData的对象成员。除外"x"外,其余的对象成员都是类。如果pData不是类对象,该项参数缺省。
n1,n2,...,nm:如果pData,"a","b",...,"x"决定的数据是数组类型,该项指出了m维数组元素的地址;否则,该项参数缺省。
&x0,&x1,&x2,...:取得的数据由这些参数返回。如果pData,"a","b",...,"x"决定的数据长度不超过8个字节,使用一个参数返回数据的值;否则参数的个数×8应等于一个该类型数据所占字节数。这些参数可以缺省。
返回值:如果pData:"a","b",...,"x"决定的数据长度不超过8个字节,直接返回数据的值,否则返回将数据截断后的值。
[例子]
实数函数get()仅简单地调用了整数函数get(),因而二者的功能完全相同,但在实数表达式中使用函数get()时,其参数要根据实际情况进行必要的转换。
[例子]
(:x)= x=new[rtoi(real_s),rtoi(5),rtoi(EndType),11.11,22.22,33.33],printf{"{1,r}/r/n",get[x,rtoi(2)]},delete[x];
[返回本类函数列表] [返回页首] set(pData:"a","b",...,"x":n1,n2,...,nm:x0,x1,x2,...):设置一个FcData数据的值
pData:FcData数据指针。
"a","b",...,"x":如果pData是类对象,该项指出了pData的对象成员。除外"x"外,其余的对象成员都是类。如果pData不是类对象,该项参数缺省。
n1,n2,...,nm:如果pData,"a","b",...,"x"决定的数据是数组类型,该项指出了m维数组元素的地址;否则,该项参数缺省。
x0,x1,x2,...:设置参数。如果pData:"a","b",...,"x"决定的数据长度不超过8个字节,使用一个参数设置数据的值;否则参数的个数×8应等于一个该类型数据所占字节数。
返回值:0。
[例子]
实数函数set()仅简单地调用了整数函数set(),因而二者的功能完全相同,但在实数表达式中使用函数set()时,其参数要根据实际情况进行必要的转换。
[例子]
(:x)= x=new[rtoi(real_s),rtoi(5),rtoi(EndType),11.11,22.22,33.33],set[x,rtoi(2),55.55],printf{"{1,r}/r/n",get[x,rtoi(2)]},delete[x];
[返回本类函数列表] [返回页首] FCDToStr(Type:x0,...:pWChar_s)或FCDToStr(pFCD,pWChar_s):将FcData数据转换为字符串
Type:FcData数据类型,只能是简单数据类型。Type不能为数组,也不能为类及类对象。
x0,...:数据。如果Type类型数据的字节数大于8,则数据个数×8等于该数据类型的字节长度。
pWChar_s:字符数组指针。
pFCD:FcData数据指针,只能是简单数据类型。pFCD不能为数组,也不能为类及类对象。
[例子1] i:(:a,b)= a=new[real,2],b=new[string,80],FCDToStr[a,b],"{1,s}/r/n".b.printf[];
[例子2]
[返回本类函数列表] [返回页首] StrToFCD(pWChar_s,Type:x0,x1,...)或StrToFCD(pWChar_s,pFCD):将字符串转换为FcData数据
pWChar_s:字符数组指针。注意:数字字符(包括符合、小数点等有效字符)必须是连续的,否则转换结果不正确。例如:不要将“-6.5e-9”写成“- 6.5e-9”。但数字前后空格不影响转换结果。
Type:FcData数据类型,只能是简单数据类型。Type不能为数组,也不能为类及类对象。
x0,x1,...:数据。如果Type类型数据的字节数大于8,则数据个数×8等于该数据类型的字节长度。
pFCD:FcData数据指针,只能是简单数据类型。pFCD不能为数组,也不能为类及类对象。
[例子1] i:(:s,a,b,j,k)=s=new[string,EndType:"-6.5e-9 -6e-5i"],a=new[complex],b=new[string,80],StrToFCD[s,complex:&j,&k],FCDToStr[complex:j,k:b],"{1,s}/r/n".b.printf[];
[例子2]
[返回本类函数列表] [返回页首] FCDstrlen(pStr)或FCDstrlen("hello!",x)或FCDstrlen(ForType,ForHandle,"hello!"):得到字符串长度
pStr:FcData字符数组指针。
x:任意值。
ForType,ForHandle:表达式的类型及句柄。ForType=1表示整数表达式,ForType=2表示实数表达式,ForType=3表示复数表达式。
说明1:FCDstrlen有一个参数时,获得FcData字符串长度;FCDstrlen有二个参数时,获得Forcal近程静态字符串长度;FCDstrlen有三个参数时,获得Forcal远程静态字符串长度。
说明2:FcData字符串或Forcal字符串以NULL结尾。
[返回本类函数列表] [返回页首] FCDstrcpy(dest,source)或FCDstrcpy(dest,"hello!",x)或FCDstrcpy(dest,ForType,ForHandle,"hello!"):复制字符串
dest:FcData目的数据指针,只能是char_s(string)或Uchar_s类型。
source:FcData数据指针,只能是char_s(string)或Uchar_s类型。
x:任意值。
ForType,ForHandle:表达式的类型及句柄。ForType=1表示整数表达式,ForType=2表示实数表达式,ForType=3表示复数表达式。
说明:FCDstrcpy有2个参数时,复制FcData字符串到目的字符串;FCDstrcpy有3个参数时,复制Forcal近程静态字符串到目的字符串;FCDstrcpy有4个参数时,复制Forcal远程静态字符串到目的字符串。
[例子1] i:(::a)= a=new[wchar_s,20,EndType,"Hello"],FCDstrcpy[a," FcData!",0],"{1,s}/r/n".a.printf[];
[例子2] i:(::a,b)= a=new[wchar_s,80,EndType,"Hello"],b=new[wchar_s,EndType," FcData!"],FCDstrcpy[a,b],printf["{1,s}/r/n",a];
[返回本类函数列表] [返回页首] FCDstrcat(dest,source)或FCDstrcat(dest,"hello!",x)或FCDstrcat(dest,ForType,ForHandle,"hello!"):连接字符串
dest:FcData目的数据指针,只能是char_s(string)或Uchar_s类型。
source:FcData数据指针,只能是char_s(string)或Uchar_s类型。
x:任意值。
ForType,ForHandle:表达式的类型及句柄。ForType=1表示整数表达式,ForType=2表示实数表达式,ForType=3表示复数表达式。
说明1:FCDstrcat有2个参数时,连接FcData字符串到目的字符串;FCDstrcat有3个参数时,连接Forcal近程静态字符串到目的字符串;FCDstrcat有4个参数时,连接Forcal远程静态字符串到目的字符串。
说明2:将源字符串连接到目的字符串dest的后面。
[例子1] i:(::a)= a=new[wchar_s,20,EndType,"Hello"],FCDstrcat[a," FcData!",0],printf["{1,s}/r/n",a];
[例子2] i:(::a,b)= a=new[wchar_s,80,EndType,"Hello"],b=new[wchar_s,EndType," FcData!"],FCDstrcat[a,b],printf["{1,s}/r/n",a];
[返回本类函数列表] [返回页首] FCDstrcmp(dest,source)或FCDstrcmp(dest,"hello!",x)或FCDstrcmp(dest,ForType,ForHandle,"hello!"):比较字符串
dest:FcData目的数据指针,只能是char_s(string)或Uchar_s类型。
source:FcData数据指针,只能是char_s(string)或Uchar_s类型。
x:任意值。
ForType,ForHandle:表达式的类型及句柄。ForType=1表示整数表达式,ForType=2表示实数表达式,ForType=3表示复数表达式。
说明:FCDstrcmp有2个参数时,与FcData字符串进行比较;FCDstrcmp有3个参数时,与Forcal近程静态字符串进行比较;FCDstrcmp有4个参数时,与Forcal远程静态字符串进行比较。
返回值:字符串相等时返回0,否则返回非0值。
[例子1] i:(::a)= a=new[wchar_s,EndType,"FcData"],FCDstrcmp[a,"FcData",0];
[例子2] i:(::a)= a=new[wchar_s,EndType,"FcData"],FCDstrcmp[a,"fcdata",0];
[例子3] i:(::a,b)= a=new[wchar_s,EndType,"FcData"],b=new[wchar_s,EndType,"FcData"],FCDstrcmp[a,b];
[返回本类函数列表] [返回页首] printf("hello!")或printf("...{...}...{...}...",x1,x2,...):格式化输出到标准设备
若printf函数只有一个参数,直接输出Forcal近程静态字符串。
若有多个参数时(参数序号以0为基数,依次为0,1,2,...),第0个参数是含格式说明的字符串,其余为要输出的参数列表。第0个字符串参数由两部分组成,第一部分是普通字符,将被输出(两个相连的左花括号“{{”被视为一个“{”);第二部分是花括号{...}内的格式说明,将按格式说明在此位置插入一个字符串。
格式说明有三项(前2项不可缺省),由逗号隔开(空格符被忽略),以{2,r,10.5}为例:第一项2指出要输出printf函数的第2个参数;第二项r表示按实数格式输出;第三项10.5表示最小输出宽度为10个字符,保留5位有效数字,靠右边输出,若是负数表示靠左输出(例如:-10.5)。有效数字说明仅对实数和复数有效,如果是一个字符串,该项表示最大输出宽度,其他类型参数将忽略该说明。一般,若最小输出宽度不够用,将按实际宽度输出,但字符串例外,超过最大输出宽度的部分将被截断。
函数返回实际输出的字符个数,出错时返回负数。
printf函数的格式说明第二项的意义见下表。
说明符 | 格式 | 例子 | 例子的说明 |
c | 单个字符 | printf{"字符{1,c},还是字符{1,c}","a"}; | |
ic | 将一个整数转换为字符 | printf{"字符{2,ic},字符{1,ic}",76,77}; | |
s | 字符串指针 | i: printf{"字符串{1,s}",new(wchar_s,EndType,"abc")}; | 用整数表达式的例子比较方便 |
ns | Forcal近程静态字符串 | printf{"字符串{1,ns}","hello!"}; | |
fs | Forcal远程静态字符串,需要三个参数 | bb()="adfg";printf["远程静态字符串{1,fs}",2,HFor("bb",2),bb()]; | 需要三个参数:表达式类型、表达式句柄、字符串地址 |
r | 双精度实数 | printf{"实数相加{1,r}+{2,r}={3,r}/r/n",23,5.6,23+5.6}; | |
f | 单精度实数 | printf{"实数相加{1,f}+{2,f}={3,f}/r/n",23,5.6,23+5.6}; | 单精度实数仅占一个数的前4个字节,故该例子输出结果不正确 |
cr | 双精度复数,需要两个参数 | printf{"复数{1,cr}{3,ns}/r/n",23,5.6,"占用两个参数"}; | 复数占用两个参数 |
cf | 单精度复数,需要两个参数 | printf{"复数{1,cf}{3,ns}/r/n",23,5.6,"占用两个参数"}; | 复数占用两个参数 |
i | 10进制整数 | printf{"10进制整数{1,i}/r/n",235.6}; | |
x | 16进制整数 | printf{"16进制整数{1,x}/r/n",235.6}; | |
i2、i3、...、i36 | 2进制整数、3进制整数、...、36进制整数 | printf{"10进制整数{1,i}的2进制数为{1,i2},8进制数为{1,i8},29进制数为{1,i29}。/r/n",2235.6}; | |
n | 将已输出的字符格式保存到关联的参数 | (:x)=printf{"字符串{1,ns}{2,n}{1,ns}","hello!",&x},x; |
[例子1]:
printf["只有一个参数时,字符串中的格式符{0,i}被忽略。"];
printf["多于一个参数时,字符串中的格式符{0,i}起作用。",55];
[例子2]:
a()="hello !";
printf["远程静态字符串{1,fs}",2,HFor("a",2),a()];
i: printf["远程静态字符串{1,fs}",2,HFor("a",2),rtoi(a())];
[例子3]:
printf{"实数{1,r}取5位有效数字{1,r, 10.5}靠右显示。/r/n",sin(2.3)};
printf{"实数{1,r}取5位有效数字{1,r,-10.5}靠左显示。/r/n",sin(2.3)};
[例子4]:
printf{"字符串{1,ns}超过最大输出宽度时将被截断:{1,ns,5.7}。/r/n","abcdefghijk"};
[例子5]:
printf{"格式说明{ 1, ns}中可以有空格:{1 , ns , 5.7 }。/r/n","abcdefghijk"};
[返回本类函数列表] [返回页首] printfs("hello!")或printfs("...{...}...{...}...",x1,x2,...,pstr):格式化输出到字符串
printfs函数的功能与printf函数类似,但将格式化字符串输出到一个字符串pstr(最后一个参数)。printfs输出到pstr时,总是连接到pstr的后面。pstr必须有足够大的缓冲区,否则将返回一个运行错误。请参考printf函数的说明。
[例子1]
i: (:ps)= ps=new[string,100,EndType,""], printfs{"字符串{1,ns}/r/n","hello!",ps}, printfs{"整数{1,i}/r/n实数{1,r}/r/n",100,ps}, printf("{1,s}",ps);
[例子2]
i: a()=new[string,100,EndType,""];
(:ps)= ps=a(), printfs{"字符串{1,ns}/r/n","hello!",ps}, printfs{"整数{1,i}/r/n实数{1,r}/r/n",100,ps}, printf("{1,s}",ps);
[返回本类函数列表] [返回页首] CSetLen(pClass,len,bufmax):设置类的大小
pClass:FcData类对象指针。
len:类的大小。
bufmax:类的缓冲区大小。若缺省该参数,默认bufmax=len。
返回值:pClass。
说明:类的缓冲区大小必须大于等于类的大小。特殊地,CSetLen(pClass,0)将清空类pClass的所有成员及缓冲区,pClass将成为空类。
[返回本类函数列表] [返回页首] CHasName(pClass,"name"):根据类成员名称测试类成员是否存在
pClass:FcData类对象指针。
"name":类成员名称。
返回值:类成员序号。若返回值小于0表示类成员不存在。
[返回本类函数列表] [返回页首] CDupName(pClass,begin,&m,&n):根据类成员名称测试类成员是否重名
pClass:FcData类对象指针。
begin:类成员地址。从该地址向后查找测试。
m,n:返回重名的类成员地址。
返回值:非0表示类成员重名。
[返回本类函数列表] [返回页首] CSetAllAttr(pClass,bDelete):设置所有类成员的属性
pClass:FcData类对象指针。
bDelete:类成员删除属性。若类成员删除属性为true,销毁类之前将销毁该类成员,否则不销毁类成员。
返回值:pClass。该函数一次性将所有类成员设置为同一删除属性。
[返回本类函数列表] [返回页首] CSD(pClass,"a"):得到基类成员指针,深度优先
pClass:FcData类对象指针。
"a":该项指出pClass的对象成员。"a"可以是一个基类的对象成员。
说明:该函数先在FcData的成员中寻找"a",若找不到,就会到该类的基类(父类)中寻找。如果有多个基类,则搜索按照基类(base class)在类定义中的顺序从左至右,深度优先,返回第一个找到的值。
注意:该函数所能操作的类层次深度受函数SetFCDRecurMax的设定值的影响,不能在一个类层次特别多的类(例如:比较长的链表,类层次有上万层)中使用该函数。
[例子]
[返回本类函数列表] [返回页首] CSB(pClass,"a"):得到基类成员指针,广度优先
pClass:FcData类对象指针。
"a":该项指出pClass的对象成员。"a"可以是一个基类的对象成员。
说明:该函数先在FcData的成员中寻找"a",若找不到,就会到该类的基类(父类)中寻找。如果有多个基类,则搜索按照基类(base class)在类定义中的顺序从左至右,广度优先,返回第一个找到的值。
注意:该函数所能操作的类层次深度受函数SetFCDRecurMax的设定值的影响,不能在一个类层次特别多的类(例如:比较长的链表,类层次有上万层)中使用该函数。
[例子]
[返回本类函数列表] [返回页首] CSetItem(pClass:"a",new(int,252),"b",Cvirtual,NotDelete,"999",NULL):根据类成员名称设置类的成员
说明:pClass是类指针,返回值仍然是pClass。该函数只能给类的有名成员赋值,给类成员赋值的顺序是任意的。在本例中,给成员"a"赋初值为new(int,252);给成员"b"赋初值为Cvirtual,Cvirtual是预先申请的FcData数据,关键字NotDelete指出,删除该类对象时,不删除Cvirtual;给成员"999"赋初值为NULL。
[返回本类函数列表] [返回页首] CSetItemI(pClass:3,new(int,252):5,Cvirtual,NotDelete:2,NULL):根据类成员地址设置类的成员
说明:pClass是类指针,返回值仍然是pClass。只要给出类成员的地址,该函数可以给任意成员赋值,给类成员赋值的顺序是任意的。在本例中,给序号为3的成员赋初值为new(int,252);给序号为5的成员赋初值为Cvirtual,Cvirtual是预先申请的FcData数据,关键字NotDelete指出,删除该类对象时,不删除Cvirtual;给序号为2的成员赋初值为NULL。
[返回本类函数列表] [返回页首] CGetNameI(pClass,"name",NStr,NStrLen):根据类成员地址获得类成员的名称
pClass:FcData类对象指针。
"name":类成员的名称。
NStr:Forcal近程字符串地址,用于存放类成员的名称。
NStrLen:Forcal近程字符串缓冲区长度。
返回值:pClass。
[例子]
[返回本类函数列表] [返回页首] CSetName(pClass,"oldname","newname"):根据类成员名称设置类成员名称
pClass:FcData类对象指针。
"oldname":类成员的原名称。
"newname":类成员的新名称。
返回值:pClass。
[返回本类函数列表] [返回页首] CSetNameI(pClass,index,"newname"):根据类成员地址设置类成员名称
pClass:FcData类对象指针。
index:类成员地址。
"newname":类成员的新名称。
返回值:pClass。
[返回本类函数列表] [返回页首] CGetP(pClass:"a","b",... ...,"x"):根据类成员名称获得类成员指针
pClass:FcData类对象指针。
"a","b",... ...,"x":该项指出pClass的对象成员。"x"可以是任意的对象成员,其余的对象成员都必须是类。
[例子]
[返回本类函数列表] [返回页首] CGetPI(pClass:i1,i2,... ...,in):根据类成员地址获得类成员指针
pClass:FcData类对象指针。
i1,i2,... ...,in:该项指出pClass的对象成员。in可以是任意的对象成员,其余的对象成员都必须是类。
[返回本类函数列表] [返回页首] CSetP(pClass:"a","b",... ...,"x":p):根据类成员名称设置类成员指针
pClass:FcData类对象指针。
"a","b",... ...,"x":该项指出pClass的对象成员。"x"可以是任意的对象成员,其余的对象成员都必须是类。
p:FcData数据指针。
返回值:pClass。
[例子]
[返回本类函数列表] [返回页首] CSetPI(pClass:i1,i2,... ...,in:p):根据类成员地址设置类成员指针
pClass:FcData类对象指针。
i1,i2,... ...,in:该项指出pClass的对象成员。in可以是任意的对象成员,其余的对象成员都必须是类。
p:FcData数据指针。
返回值:pClass。
[返回本类函数列表] [返回页首] CGetA(pClass:"a","b",... ...,"x"):根据类成员名称获得类成员属性
pClass:FcData类对象指针。
"a","b",... ...,"x":该项指出pClass的对象成员。"x"可以是任意的对象成员,其余的对象成员都必须是类。
说明:若类成员删除属性为true,销毁类之前将销毁该类成员,否则不销毁类成员。
[返回本类函数列表] [返回页首] CGetAI(pClass:i1,i2,... ...,in):根据类成员地址获得类成员属性
pClass:FcData类对象指针。
i1,i2,... ...,in:该项指出pClass的对象成员。in可以是任意的对象成员,其余的对象成员都必须是类。
说明:若类成员删除属性为true,销毁类之前将销毁该类成员,否则不销毁类成员。
[返回本类函数列表] [返回页首] CSetA(pClass:"a","b",... ...,"x":bDelete):根据类成员名称设置类成员属性
pClass:FcData类对象指针。
"a","b",... ...,"x":该项指出pClass的对象成员。"x"可以是任意的对象成员,其余的对象成员都必须是类。
bDelete:类成员删除属性。若类成员删除属性为true,销毁类之前将销毁该类成员,否则不销毁类成员。
返回值:pClass。
[返回本类函数列表] [返回页首] CSetAI(pClass:i1,i2,... ...,in:bDelete):根据类成员地址设置类成员属性
pClass:FcData类对象指针。
i1,i2,... ...,in:该项指出pClass的对象成员。in可以是任意的对象成员,其余的对象成员都必须是类。
bDelete:类成员删除属性。若类成员删除属性为true,销毁类之前将销毁该类成员,否则不销毁类成员。
返回值:pClass。
[返回本类函数列表] [返回页首] CAdd(pClass,pC):类相加
pClass:FcData类对象指针。
pC:FcData类对象指针。
返回值:pClass。
说明:该函数将类pC的成员添加到类pClass的末尾,若类pClass的缓冲区不够用,返回一个运行错误。
[返回本类函数列表] [返回页首] CAppend(pClass,"name",value,bDelete):在类的末尾追加成员
pClass:FcData类对象指针。
"name":类成员名称。
value:类成员。
bDelete:类成员删除属性。
返回值:pClass。
说明:若类缓冲区不够用,返回一个运行错误。
[返回本类函数列表] [返回页首] CInsert(pClass,"thename","name",value,bDelete):根据类成员名称在类中插入成员
pClass:FcData类对象指针。
"thename":类成员名称,在此位置插入新成员。
"name":类成员名称。
value:类成员。
bDelete:类成员删除属性。
返回值:pClass。
说明:本函数在"thename"处插入新成员,原"thename"及后面的成员后退。若类缓冲区不够用,返回一个运行错误。
[返回本类函数列表] [返回页首] CInsertI(pClass,i,"name",value,bDelete):根据类成员地址在类中插入成员
pClass:FcData类对象指针。
i:类成员地址。
"name":类成员名称。
value:类成员。
bDelete:类成员删除属性。
返回值:pClass。
说明:本函数在i处插入新成员,原i及后面的成员后退。若类缓冲区不够用,返回一个运行错误。
[返回本类函数列表] [返回页首] CPop(pClass,&bDelete):返回类的最后一个成员,类长度减1
pClass:FcData类对象指针。
bDelete:返回删除属性,可以缺省该参数。
说明:若类为空,使用该函数将返回运行错误。
[返回本类函数列表] [返回页首] CSort(pClass,IFor):类成员排序
pClass:FcData类对象指针。
IFor:自定义二元函数句柄,用于比较类成员的大小。格式为IFor(i,j):若i>j,返回正数;若i=j,返回0;若i<j,返回负数。
返回值:pClass。
说明:该函数将类成员自小到大进行稳定排序,两个类成员大小的比较由自定义函数IFor(i,j)确定。
[例子1] 类成员是FcData数据
i::comp(i,j) = i.get()-j.get(); //定义比较类成员大小的函数
i::ab() = new[class,EndType:"a","b","c","d","e"];//定义申请类的函数ab
i:b(::a) = a=ab().CSetItem{ //申请ab类型的类对象并赋初值
"a",new[int,3],
"b",new[int,7],
"c",new[int,9],
"d",new[int,6],
"e",new[int,8]
};
i:c(::a) = OutClass[a,8]; //输出类a的结构
i:d(::a) = a.CSort[HFor("comp")];//排序
i:e(::a) = OutClass[a,8]; //输出类a的结构
i:f(::a) = delete[a]; //删除类对象a
[例子2] 类成员是一个数
i::comp(i,j) = i-j; //定义比较类成员大小的函数
i::ab() = new[class,EndType:"a","b","c","d","e"];//定义申请类的函数ab
i:b(::a) = a=ab().CSetItem{ //申请ab类型的类对象并赋初值
"a",3,
"b",7,
"c",9,
"d",6,
"e",8
};
i:c(::a) = a.CSetAllAttr(false); //设置所有类成员不自动删除
i:d(::a) = OutClass[a,8]; //输出类a的结构
i:e(::a) = a.CSort[HFor("comp")];//排序
i:f(::a) = OutClass[a,8]; //输出类a的结构
i:g(::a) = delete[a]; //删除类对象a
[返回本类函数列表] [返回页首] CDFSBase(pClass,pArray):深度搜索类的基类
pClass:FcData类对象指针。
pArray:Uint64_s或int64_s一维数组指针,存放搜索到的基类(包含pClass,pClass为数组的第一个元素)。
返回值:搜索到的基类个数(包含pClass)。如果返回值等于数组pArray的大小,可能没有搜索完。
[例子]
4.1 类
除了FcData固有的基本数据类型外,用户还可以通过类定义自己的数据类型。类是一种包含多种类型的数据并可自动销毁这些数据的数据结构。类是组合型数据类型,它一般由一个或多个成员组成,形成一个独立的逻辑单元。与数组不同的是,类中的成员可以是不同的数据类型。在销毁类时,类中包含的数据可自动销毁(也可指定为不自动销毁)。类是一种动态的数据结构,类的结构随程序的运行会不断发生变化。
类的结构很简单,有以下几个组成部分:
(1)类长度:也称类的大小,表示有几个类成员。
(2)类成员:一般是FcData数据指针,当然可以是任意的数据类型,或者是一个纯粹的数。
(3)类成员序号:也称类成员地址。类成员在类中是连续存放的(采用一维数组的存放方式),因而每个成员对应一个序号,起始序号为0。如果类长度为n,则类成员序号取0,1,2,... ...,n-1。
(4)类成员名称:用字符串标识类成员名称。每个类成员名称对应一个类成员序号,即对应一个类成员。类成员名称可以缺省。根据名称访问类成员比根据序号访问类成员效率低,但比较直观。
(5)类成员属性:该属性标记删除类时是否删除该类成员,缺省是删除类成员。
(6)类缓冲区:类保存在类缓冲区中。像类长度一样,类缓冲区的大小也用一个正数表示。类缓冲区的大小应大于等于类的长度。
通过关键字class申请一个类。例如:new(class,5,8,"a","b",... ...),定义了一个包含5个成员的类,保存在可存放8个成员的缓冲区中。字符串"a","b",... ...定义了类的成员,每一个字符串标识一个类成员,区分大小写。注意类成员名称不要重复,否则后定义的类成员将无法访问。在类定义时无法确定类成员的类型,类成员的类型在给类对象赋值时确定,类成员的类型可以是一个类对象。
定义完类后,可以通过函数CSetItem(pClass:"a",x:"b",y,NotDelete:... ...)给类的成员赋值。pClass是类指针。本例中,给成员"a"赋初值为x;给成员"b"赋初值为y,关键字NotDelete指出,删除该类对象时,不删除y。一般情况下,x和y都是FcData数据指针,当然也可以是任意的数。
每一个类成员都有删除属性,如果属性为true,在销毁类对象时,将先销毁该类成员,如果属性为false,将不销毁该类成员。在创建类对象时,类成员的删除属性缺省情况下为true,但可以用关键字NotDelete指明该类成员的删除属性为false。对于已经存在的类对象,可以用函数CGetA()和CSetA()获得或设置类成员及属性。
一般情况下,类成员是一个FcData数据指针,类成员的类型即FcData数据类型。FcData数据可以用函数set()获得,用函数set()进行设置,而数据指针用函数CGetP()获得,用函数CSetP()进行设置。当然,也可以将数据指针本身当作数据,而不管数据指针是否有效,实际上,数据指针就是一个4字节整数。
类可以为空。如果非空,FcData约定类的第一个成员作为该类的名称。但类的名称不是该类的唯一标识,类的唯一标识是类指针。FcData允许多个类的名称相同,为了区分不同的类,要为每个类起一个不同的名字。
如果类A是类B的成员,则称类A为类B的基类(父类),类B为类A的派生类(子类)。类可以多重继承,也可以形成循环链表互为基类或派生类。可以用函数CSD()或CSB()获得基类的对象成员,这两个函数搜索基类对象成员的方法不同,CSD()是深度优先的,而CSB()广度优先。
在FcData中有许多对类进行操作的函数,这些函数均以大写字母C开头。这些函数中,有些是根据类成员名称对类进行操作的,有些是根据类成员地址对类进行操作,根据类成员地址对类进行操作的函数均以大写字母I结尾。
对每一种特定的类对象,都设计一个专门的函数来创建它,这样容易实现类的继承。
设计一个模块,专门用来处理有特定意义的类,这样的模块称为类模块。通过模块变量、模块的私有函数(仅模块内使用的表达式),可以实现对数据处理的封装和隐藏,通过模块的公有函数(可供其他模块调用的表达式),可以输出模块的功能。
下面的类给出了一个人的简单信息:
person=new(class,EndType:"姓名","性别","年龄");
给类对象赋值:
person.CSetItem{
"姓名",new(char_s,EndType,"王强"),
"性别",new(char_s,EndType,"男"),
"年龄",new(int,23)
};
获得并输出类对象的值:
printf["{1,s}",person."姓名".CGetP()];
printf["{1,s}",person."性别".CGetP()];
printf["{1,i}",person."年龄".get()];
以下是一些类的使用的例子,其中用到了函数OutClass,可以输出类的结构:
例子1:申请类对象并赋初值
i::ab() = new[class,EndType:"a","b"]; //定义申请类的函数ab,有两个类成员
i:b(::a) = a=ab().CSetItem{ //申请ab类型的类对象并赋初值
"a",new[int,89], //给类成员"a"赋初值为整数89
"b",new[int,-1289] //给类成员"b"赋初值为整数-1289
};
i:c(::a) = a."a".get[];//获得类成员"a"的值
i:d(::a) = a."b".get[];//获得类成员"b"的值
i:e(::a) = OutClass[a,8]; //输出类a的结构
i:f(::a) = delete[a]; //删除类对象a
例子2:申请类对象并通过CSetP()赋值
i::ab() = new[class,EndType:"a","b"]; //定义申请类的函数ab,有两个类成员 i:b(::a) = a=ab(); //申请ab类型的类对象 i:c(::a) = a."a".CSetP[new(int,89)], //给类成员"a"赋值为整数89 a."b".CSetP[new(int,-1289)]; //给类成员"b"赋值为整数-1289 i:d(::a) = a."a".CGetP[]; //得到类成员"a"的指针 i:e(::a) = a."a".get[]; //获得类成员"a"的值 i:f(::a) = a."b".CGetP[]; //得到类成员"b"的指针 i:g(::a) = a."b".get[]; //获得类成员"b"的值 i:h(::a) = a."a".set[-123]; //给类成员"a"的重新赋值 i:i(::a) = a."a".get[]; //获得类成员"a"的值 i:j(::a) = OutClass[a,8]; //输出类a的结构 i:k(::a) = delete[a]; //删除类对象a
例子3:循环链表及删除方法1
i::ab() = new[class,EndType:"a","b"]; //定义申请类的函数ab,有两个类成员 i:b(::a,b) = a=ab().CSetItem{"a",new[int,89]}, //申请ab类型的类对象a并赋初值为整数89 b=ab().CSetItem{"a",new[int,-89]}; //申请ab类型的类对象b并赋初值为整数-89 i:c(::a,b) = a."b".CSetP[b]; //让类对象a的类成员"b"指向类对象b i:d(::a,b) = b."b".CSetP[a]; //让类对象b的类成员"b"指向类对象a,形成循环链表 i:e(::a) = a."a".get[]; //获得类对象a的类成员"a"的值 i:f(::a) = a."b"."a".get[]; //获得类对象b的类成员"a"的值 i:g(::a) = a."b"."b"."a".get[]; //获得类对象a的类成员"a"的值 i:h(::a) = a."b"."b"."b"."a".get[]; //获得类对象b的类成员"a"的值 i:i(::a) = a."b"."b"."b"."b"."a".get[]; //获得类对象a的类成员"a"的值 i:j(::a) = OutClass[a,8]; //输出类a的结构 i:k(::a) = delete[a]; //删除类对象a、b
例子4:循环链表及删除方法2
i::ab() = new[class,EndType:"a","b"]; //定义申请类的函数ab,有两个类成员 i:b(::a,b) = a=ab().CSetItem{"a",new[int,89]}, //申请ab类型的类对象a并赋初值为整数89 b=ab().CSetItem{"a",new[int,-89]}; //申请ab类型的类对象b并赋初值为整数-89 i:c(::a,b) = a."b".CSetP[b]; //让类对象a的类成员"b"指向类对象b i:cc(::a,b) = a."b".CSetA[false]; //让类对象a的类成员"b"不能自动删除 i:d(::a,b) = b."b".CSetP[a]; //让类对象b的类成员"b"指向类对象a i:dd(::a,b) = b."b".CSetA[false]; //让类对象b的类成员"b"不能自动删除 i:e(::a) = get[a:"a"]; //获得类对象a的类成员"a"的值 i:f(::a) = get[a:"b","a"]; //获得类对象b的类成员"a"的值 i:g(::a) = get[a:"b","b","a"]; //获得类对象a的类成员"a"的值 i:h(::a) = get[a:"b","b","b","a"]; //获得类对象b的类成员"a"的值 i:i(::a) = get[a:"b","b","b","b","a"]; //获得类对象a的类成员"a"的值 i:j(::a,b) = OutClass[a,8],OutClass[b,8]; //输出类a、b的结构 i:k(::a) = delete[a]; //删除类对象a,类对象b没有删除 i:l(::b) = delete[b]; //删除类对象b
例子5:给任意字符串创建单链表,并按字符从小到大排序
i:a(::str) = str=new[wchar_s,EndType:"q8 af580f b"]; //定义任意字符串 i::Cstr() = new[class,EndType:"ch","pnext"]; //定义申请类的函数Cstr,有两个类成员 i:c(::head) = head=Cstr().CSetItem{"ch",new(Uint16,0),"pnext",NULL}; //申请头结点,存储最小字符代码0 i:d(:i,ch,p,pStr:head,str) = i=0,pStr=head,while{1, //按字符串创建链表 ch=str.get(i), p=Cstr().CSetItem{"ch",new(Uint16,ch):"pnext",NULL}, pStr."pnext".CSetP[p], pStr=p, if[!ch,break()], i++ }; i:e(:bEx,end,pp,p,k:head) = end=NULL,while{end!=head, //冒泡法排序,按字符从小到大排序 bEx=false,pp=head,p=pp."pnext".CGetP[], //end和bEx可减少比较次数 while{p!=end, if[pp."ch".get()>p."ch".get(),bEx=true,k=pp."ch".get(),pp."ch".set(p."ch".get()),p."ch".set(k)], pp=p,p=p."pnext".CGetP[] }, if(!bEx,break()), end=pp }; i:f(:str80,p:head) = str80=new[wchar_s,80], //输出排序后的字符 p=head."pnext".CGetP[], while{p, FCDToStr[wchar,get(p,"ch"),str80],printf["{1,s}",str80], p=p."pnext".CGetP[] }, delete[str80]; i:g(::head) = OutClass[head,20]; //输出类head的结构 i:h(::head,str) = delete[head],delete[str]; //删除类对象、类定义及字符串
例子6:类的继承
以下类的继承实现了如下类层次关系,可看作一棵树。
"c":a-->"a":11
|
"e":cd-->|
| |
| "d":44
ef-->|
| "a":22
| |
"f":ab-->|
|
"b":33
i::A()= new[class,EndType:"a"]; //类定义,有一个类成员
i::AB() = new[class,EndType:"a","b"];//类定义,有两个类成员
i::CD() = new[class,EndType:"c","d"]; //类定义,有两个类成员
i::EF() = new[class,EndType:"e","f"];//类定义,有两个类成员
i:e(::a,ab,cd,ef) =
{ a=A().CSetItem{"a":new(int,11)},//申请A类型的类对象并赋初值
ab=AB().CSetItem{"a":new(int,22),"b":new(int,33)}, //申请AB类型的类对象并赋初值
cd=CD().CSetItem{"c":a,"d":new(int,44)},//申请CD类型的类对象并赋初值
ef=EF().CSetItem{"e":cd,"f":ab} //申请EF类型的类对象并赋初值
};
i:f(::ef) = ef.CSD("a").get[]; //深度优先,获得间接基类成员a-->"a":11
i:g(::ef) = ef.CSB("a").get[]; //广度优先,获得直接基类成员ab-->"a":22
i:h(::ef) = ef.OutClass[10];//输出类ef的结构
i:i(::ef) = delete[ef]; //删除类对象ef
例子7:类的循环继承
以下类的继承实现了如下类层次关系,可看作一张连通图。
"c":a-->"a":11
|
"e":cd-->|
| |
| "d":ef
ef-->|
| "a":22
| |
"f":ab-->|
|
"b":33
i::A()= new[class,EndType:"a"]; //类定义,有一个类成员
i::AB() = new[class,EndType:"a","b"];//类定义,有两个类成员
i::CD() = new[class,EndType:"c","d"]; //类定义,有两个类成员
i::EF() = new[class,EndType:"e","f"];//类定义,有两个类成员
i:e(::a,ab,cd,ef) =
{ a=A().CSetItem{"a":new(int,11)},//申请A类型的类对象并赋初值
ab=AB().CSetItem{"a":new(int,22),"b":new(int,33)}, //申请AB类型的类对象并赋初值
cd=CD().CSetItem{"c":a}, //申请CD类型的类对象并赋初值
ef=EF().CSetItem{"e":cd,"f":ab},//申请EF类型的类对象并赋初值
cd.CSetItem{"d":ef} //构成循环类
};
i:f(::ef) = ef.CSD("a").get[]; //深度优先,获得间接基类成员a-->"a":11
i:g(::ef) = ef.CSB("a").get[]; //广度优先,获得直接基类成员ab-->"a":22
i:h(::ef) = ef.OutClass[10];//输出类ef的结构
i:i(::ef) = delete[ef]; //删除类对象ef
例子8:用类模拟堆栈stack:必须给类预留一定的缓冲区
i:a(::a)= a=new[class,0,10]; //定义一个类,缓冲区大小为10,但没有任何成员
i:b(::a) = a.OutClass[10]; //输出类a的结构
i:c(::a) = a.CAppend["one",1]; //压栈
i:d(::a) = a.OutClass[10]; //输出类a的结构
i:e(::a) = a.CAppend["two",2]; //压栈
i:f(::a) = a.OutClass[10]; //输出类a的结构
i:g(::a) = a.CPop[]; //出栈
i:h(::a) = a.OutClass[10]; //输出类a的结构
i:i(::a) = a.CAppend["three",3]; //压栈
i:j(::a) = a.OutClass[10]; //输出类a的结构
i:k(::a) = delete[a]; //删除类对象a
例子9:用类模拟队列queue:必须给类预留一定的缓冲区
i:a(::a)= a=new[class,0,10]; //定义一个类,缓冲区大小为10,但没有任何成员
i:b(::a) = a.OutClass[10]; //输出类a的结构
i:c(::a) = a.CInsertI[0,"one",1]; //入队
i:d(::a) = a.OutClass[10]; //输出类a的结构
i:e(::a) = a.CInsertI[0,"two",2]; //入队
i:f(::a) = a.OutClass[10]; //输出类a的结构
i:g(::a) = a.CPop[]; //出队
i:h(::a) = a.OutClass[10]; //输出类a的结构
i:i(::a) = a.CInsertI[0,"three",3]; //入队
i:j(::a) = a.OutClass[10]; //输出类a的结构
i:k(::a) = delete[a]; //删除类对象a
注意:用类模拟大的队列queue效率很低,因为函数CInsert将移动大量数据。使用类,将队列设计成链表形式将大幅提高效率。
4.2 Forcal和FcData中类的特点
所有的面向对象语言(OOP语言)都具有三个共同的特征:封装性、多态性和继承性。OOP语言中的类一般有公有数据、私有数据、公有函数和私有函数。在类的外部无法访问类的私有数据,也无法调用类的私有函数。在一般的语言中,类的公有数据、私有数据、公有函数和私有函数都需要在类的定义中说明。如果是静态语言,编译器将在编译时检查源代码中类的成员使用是否合法,若不合法将给出错误信息;在动态语言中,一般在运行时进行这项检查,若不合法,也将给出错误信息。有些高级语言如C++,通过运算符重载和函数重载实现编译时的多态性,通过虚函数实现运行时的多态性。
Forcal实现了面向对象的大多数特征,但与一般的语言相比,也有一些重要的区别。在Forcal中,任何一个数据都可以看作是一个对象,任何一个函数都可以看作是对象的成员函数。对象能否被函数处理,需要在运行时才能确定,若不能处理,将给出运行错误。Forcal未将函数绑定到类的说明中,似乎不符合类的常规定义,但对一个动态语言来说,这是无关紧要的。试想一下,将函数绑定到类中,运行时检查函数使用是否合法,与不将函数绑定到类中,运行时检查函数的参数使用是否合法,二者似乎没有太大差别。
Forcal中的模块,实现了对私有数据和函数的封装,模块通过输出公有函数与外界交换信息。Forcal中可实现在运行时查找运行一个已存在的函数,或者即时编译运行一个函数,支持运行时的多态性。不过,Forcal中目前不支持运算符的重载,以后也不一定增加该功能,因为重载运算符是靠定义函数实现的,使用函数完全可以完成相同的功能,在动态语言中重载运算符会使编译器变得臃肿低效。
在Forcal扩展动态库FcData中实现了类。FcData中的类是简洁高效的,类的成员都是公有数据,每一个数据可看作一个对象,所有的数据都通过特定的函数进行存取,在类中无需定义成员函数。要想使用私有数据和函数,把类放到模块(称类模块)中就可以了。FcData中的类及成员之间有自然的继承性,而且可以通过循环链表实现相互继承。FcData中的类层次关系是一棵树或一个连通图。缺省情况下,在FcData中销毁一个类对象时,所有的基类对象也一并销毁,在类对象以循环链表的方式相互继承的情况下也是这样。
5 在实数或复数表达式中使用FcData数据
在整数表达式中申请的FcData数据,可直接在实数或复数表达式中使用,FcData数据是用指针进行标识的,在不同类型的表达式间传递一个指针时,无需进行类型转换。
在实数表达式或复数表达式中,可以用函数delete(pFCD)直接删除FcData数据,pFCD为一个FcData数据指针。
6 FcData数据的自动初始化和销毁
通过静态变量,Forcal表达式可以进行初始化,也可以借助专用静态变量free进行销毁表达式前的释放工作(Forcal在销毁表达式前将自动设置free=1,然后自动执行表达式)。当一个表达式中直接调用的其他表达式或二级函数被删除,该表达式将不能运行,这样即便在该表达式中定义了静态变量free,在Forcal销毁该表达式前也无法执行该表达式,为了在这种情况下仍能顺利地销毁申请的FcData数据,必须将自动销毁的变量用介于static和free之间的静态变量标识,如下例:
i:f(x:y,static,a,b,free,ini)=
{ if{!ini,ini=1,a=new(char),b=new(int)},//初始化,注意静态变量ini使初始化仅执行一次。
if{free,delete(a),delete(b),return(0)}, //由于a,b介于static和free之间,即便表达式不能运行,FcData也能协助Forcal销毁a,b指向的数据。
x+1 //每次调用使自变量增1。
};
i:f(0);
为了充分发挥静态变量free的作用,在表达式中不要对其有任何的赋值运算,以免引起混乱。另外,如果没有将free定义为静态变量,Forcal在销毁表达式前将不会将其自动设置为1,也不会自动执行表达式。
即便表达式中没有进行释放工作,Forcal和FcData最后也将释放所有资源,因而无需担心太多。
7 效率 [返回页首] [返回目录]
经初步测试,FcData的效率约为C++效率的1/20~1/50。以下是一些提高编程效率和执行效率的方法。
(1)用匈牙利命名法标识变量(所有的变量,包括FcData数据):以小写字母作为变量名的前缀,以说明变量的数据类型,其余部分用来描述该变量的意义与功能。
(2)对操作频繁的类成员,先用函数CGetP()、CSD()或CSB()获得类成员的指针,然后用函数get()或set()对成员进行操作,可提高执行效率。特别对基类成员更应如此。
(3)及时销毁不用的FcData数据。但如果一个FcData数据仅在某个表达式中使用,该表达式使用很频繁,可用静态变量标识该FcData数据,该FcData数据仅在表达式初始化时申请一次,不用显示地释放,最后由系统来销毁它。如下例所示:
name(x,y : static,pFCD,free) = {
if[!static,static=1,pFCD=new(...)], //表达式初始化
if{free,delete(pFCD),return(0)}, //自动销毁数据
x=...,//其他运算
y=...
};
如果一个FcData数据仅在某个模块中使用,也可以使用以上方法。
(4)为每一个表达式起一个名字。在FcData中出现运行错误时,FcData会显示出错的表达式名称。
(5)调试时,用函数NowFCDNum()检查有哪些数据没有及时释放,及时释放应该释放的FcData数据。
(6)使用类的按地址访问的函数操作类的成员。例如使用CGetPI()而不使用CGetP()。
8 FcData32W.dll中的输出函数 [返回页首] [返回目录]
FcData是一个标准的Forcal扩展动态库,共输出了6个函数,其中一个即标准的Forcal扩展动态库输出函数FcDll32W(...)。在加载FcData并初始化之后,也可以用SearchKey("RegFcDataType",FC_PrivateKey_User);、SearchKey("IsFcData",FC_PrivateKey_User);、SearchKey("NewFcDataArray",FC_PrivateKey_User);、SearchKey("DelFcDataArray",FC_PrivateKey_User);和SearchKey("FcDataClass",FC_PrivateKey_User);获得另外5个函数的句柄。输出这5个函数可使FcData能更好地用在没有指针的编程语言中,例如 VB 。这5个函数的功能和用法如下:
8.1 注册FcData数据:fcdTYPE _stdcall RegFcDataType(int Mode,void *NewFCD,void *DeleteFCD,void *OpFCD);
说明:注册FcData数据。可注册或销毁外部基本数据类型和扩展数据类型,外部基本数据类型在销毁时必须提供删除函数,扩展数据类型可被随意销毁。
Mode=1:申请一个外部基本数据类型,NewFCD为申请该数据类型的函数指针,DeleteFCD为释放该数据类型的函数指针,OpFCD为操作该数据类型的函数指针(可以为0,不能操作数据);申请失败时返回0。
Mode=2:申请一个数据类型,NewFCD为一个fcINT型指针,指向已存在的FcData数据类型标识,DeleteFCD无意义;申请失败时返回0。
Mode=0:删除一个数据类型,NewFCD为一个fcINT型指针,指向已存在的FcData数据类型标识,若NewFCD为外部基本数据类型,DeleteFCD必须为释放该数据类型的函数指针;删除失败时返回0。
函数说明:
void *(_stdcall *NewFCD)(void ); //该函数申请一个外部FcData数据。
void (_stdcall *DeleteFCD)(void *pFCD); //该函数删除pFCD,pFCD是一个外部FcData数据指针。
//该函数对外部FcData数据进行操作,成功时返回非0值,失败时返回0。mode=0时进行数据复制,desFCD为目的操作数,souFCD为源操作数。其他的mode没有定义。
int (_stdcall *OpFCD)(int mode,void *&desFCD,void *&souFCD);
说明:当注册新数据类型成功,在Forcal源代码中使用函数new(NewType)申请该类型数据时,FcData将调用函数NewFCD()申请新数据;当在Forcal源代码中使用函数delete(pFCD)销毁该数据时,FcData将调用函数DeleteFCD(pFCD)销毁该数据;当在Forcal源代码中使用函数copy(...)复制对象时,FcData将调用函数OpFCD(0,desFCD,souFCD)复制数据。
注意:注册FcData数据的模块必须在释放FcData之前调用RegFcDataType(0,NewFCD,DeleteFCD,0)注销所注册的外部基本数据类型。用RegFcDataType(2,NewFCD,DeleteFCD,0)模式注册的FcData数据类型可不必注销。
8.2 判断是否是FcData数据:fcdTYPE _stdcall IsFcData(fcIFOR pFCD,fcdTYPE &BasicType);
pFCD:FcData数据指针。
BasicType:返回FcData基本数据类型。
返回值:返回FcData扩展数据类型,返回0表示不是FcData数据。
说明:FcData内置数据类型是一个Forcal整数常量,可通过Forcal的输出函数ExMsgWithForcal(Key_IntConst,"char",Msg1,Msg2)查询。
8.3 申请FcData数组数据:bool _stdcall NewFcDataArray(fcdTYPE BType,fcVOID *SeedDimension,fcVOID *&Dimension,void *&ArrayS);
BType:FcData基本数组类型。注意:只能是数组类型。
SeedDimension:FcData数组描述。SeedDimension[0]为需申请的数组Dimension的长度,SeedDimension[1]为需申请的数组ArrayS的长度,SeedDimension[2...]为多维数组ArrayS各维数大小。
Dimension:返回FcData数组描述指针。返回时,将SeedDimension中的内容复制到Dimension中。
ArrayS:返回指向数据的指针,多维数据存在一维数组中。
返回值:返回true表示申请成功。
说明:用函数NewFcDataArray申请的数组可以替换FcData数组数据类型。替换很简单,仅进行相应的指针赋值即可。替换之前或之后,要用函数DelFcDataArray销毁原先的FcData数组数据。
参考:在其他模块中使用FcData数据。
8.4 销毁FcData数组数据:void _stdcall DelFcDataArray(fcVOID *Dimension,void *ArrayS);
Dimension:FcData数组描述指针。
ArrayS:指向数据的指针,多维数据存在一维数组中。
说明:由函数NewFcDataArray申请的FcData数组数据如果没有使用,需用该函数销毁。或者销毁被NewFcDataArray申请的FcData数组数据替换的内容。
参考:在其他模块中使用FcData数据。
8.5 操作FcData类数据:bool _stdcall FcDataClass(void *vFor,fcIFOR pClass,int mode,fcVOID &BufMax,fcVOID &Len,fcIFOR *&Value,wchar_t **&name,bool *&bFree);
vFor:从二级函数获得的表达式句柄。
pClass:类指针,FcData直接操作该指针,不进行验证。
mode:工作模式,mode=0获得类信息,mode=1申请类成员并初始化,mode=2销毁mode等于1时申请的类成员,mode=3设置类成员但不销毁包含的数据(仅销毁旧的类缓冲区,不销毁类成员,也不销毁类成员名称),mode=4设置类成员并销毁包含的数据(销毁旧的类缓冲区,按删除属性销毁类成员,并销毁类成员名称)。
BufMax:类缓冲区的大小。
Len:类的大小。
Value:类成员指针。
name:类成员名称指针。
bFree:类成员属性指针。
返回值:操作成功返回true,失败返回false。
说明:任何时候须保证类缓冲区中的未使用区域初始化为以下值:类成员设为NULL,类成员名称设为NULL,类成员属性设为true。如果mode=1申请了类成员但没有使用(例如使用mode=4但返回了false),须使用mode=2进行销毁。使用mode=4可能导致pClass无效(pClass是一个循环类),再次使用pClass时须进行检验。
9 在其他模块中使用FcData数据 [返回页首] [返回目录]
在其他模块(例如动态库)中使用FcData数据是非常简单的。只需记住在使用之前必须用函数IsFcData(pFCD,BasicType)判断指针pFCD是否合法就可以了,该函数将返回FcData数据的类型。
FcData基本数据类型的结构如下:
(1)简单数据类型:指针直接指向该数据。例如:在c++语言中,若指针pFCD的类型为“real”,则*(double *)pFCD可以直接取该数据的值。
(2)数组数据类型:数组结构是类似的,以双精度实数数组为例,结构如下:
struct FCDArrayS{
fcINT *Dimension; //Dimension[0]为数组Dimension长度,Dimension[1]为数组ArrayS长度,Dimension[2...]为多维数组ArrayS各维数大小
double *ArrayS; //指向数据的指针,多维数据存在一维数组中
};
注意:FcData数据的申请和销毁是由FcData来管理的。改变数组数据的维数和大小,即修改Dimension和ArrayS指针时,按以下步骤进行:
1)用函数IsFcData(pFCD,BasicType)判断指针pFCD是否合法,同时获得FcData数组基本类型BasicType。
2)用函数NewFcDataArray(BasicType,SeedDimension,NewDimension,NewArrayS)申请数组数据。其中SeedDimension内要预先设置数组信息,该信息将被复制到申请的数组NewDimension中,用户应保证SeedDimension中的信息规范有效。
3)对数组NewArrayS赋初值。
4)用函数DelFcDataArray(Dimension,ArrayS)删除原先的数组数据。
5)修改指针:Dimension=NewDimension,ArrayS=NewArrayS。
(3)类数据类型:没有提供类的结构,因为以后类结构或许会有些变化,但类的基本组成将保持不变。函数FcDataClass可操作类的基本组成部分:类缓冲区大小、类大小、类成员、类成员名称、类成员属性。
在其他模块(例如动态库)中访问FcData数据时,需要设计Forcal二级函数并进行注册,在Forcal二级函数中访问FcData数据。
10 通过其他模块扩展FcData数据 [返回页首] [返回目录]
(1)通过函数ExMsgWithForcal(7,void *hMsg,void *&Msg1,void *&Msg2)获得FcData向Forcal注册的数据类型标识,如char、int等。
(2)通过函数RegFcDataType(Mode,NewFCD,DeleteFCD,OpFCD)向FcData注册数据类型。
(3)设计并注册Forcal二级函数,通过二级函数及IsFcData(pFCD,BasicType)使用向FcData注册的数据类型,或者使用FcData基本数据类型。
(4)在释放FcData之前调用RegFcDataType(0,NewFCD,DeleteFCD,0)注销所注册的数据类型。
如果仅仅是使用FcData数据,则仅使用步骤(1)和(3)就可以了。
版权所有© Forcal数学软件 2008-2009,保留所有权利
E-mail: forcal@sina.com QQ:630715621
最近更新: <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%Y年%m月%d日" startspan -->2009年09月01日<!--webbot bot="Timestamp" i-checksum="1284" endspan -->