FcData32.DLL V1.0(beta版) 用户指南
| 初级用户部分:在Forcal源程序中使用FcData 1 什么是FcData 2 FcData常量 3 FcData函数 4 类 5 在实数或复数表达式中使用FcData数据 6 FcData数据的自动初始化和销毁 7 效率 | 高级用户部分:在高级语言中使用FcData数据或利用高级语言扩展FcData的功能 8 FcData32.dll中的输出函数 9 在其他模块中使用FcData数据 10 通过其他模块扩展FcData数据 |
正文:
FcData32.dll是一个标准的Forcal扩展动态库,该库对Forcal的数据类型进行了扩展。
FcData中的所有数据都用一个指针进行标识,通过指针可以访问到FcData数据。在Microsoft32位平台上,FcData指针是一个4字节整数,与Forcal整数表达式中使用的数据字节数相同。FcData是通过Forcal整数表达式实现的。
FcData中的内置基本数据类型包括简单数据和数组,如下表所示:
| 数据类型 | 说明 | 单个数据字节数 | 取值范围 | 备注 |
| char | 字符 | 1 | -128~127 | |
| Uchar | 无符号字符 | 1 | 0~255 | |
| int16 | 短整数 | 2 | -32768~32767 | |
| Uint16 | 无符号短整数 | 2 | 0~65535 | |
| int32,int | 整数 | 4 | -2147483648~2147483647 | |
| Uint32 | 无符号整数 | 4 | 0~4294967295 | |
| int64 | 长整数 | 8 | -9223372036854775808~9223372036854775807 | 缺少相应的运算函数 |
| Uint64 | 无符号长整数 | 8 | 0~18446744073709551615 | 缺少相应的运算函数 |
| real32 | 单精度实数 | 4 | -3.4E-38~3.4E-38 | |
| real64,real | 双精度实数 | 8 | -1.7E-308~1.7E-308 | |
| complex | 复数 | 16 | -1.7E-308~1.7E-308 | |
| char_s,string | 字符数组 | 1 | -128~127 | |
| Uchar_s | 无符号字符数组 | 1 | 0~255 | |
| int16_s | 短整数数组 | 2 | -32768~32767 | |
| Uint16_s | 无符号短整数数组 | 2 | 0~65535 | |
| int32_s,int_s | 整数数组 | 4 | -2147483648~2147483647 | |
| Uint32_s | 无符号整数数组 | 4 | 0~4294967295 | |
| int64_s | 长整数数组 | 8 | -9223372036854775808~9223372036854775807 | 缺少相应的运算函数 |
| Uint64_s | 无符号长整数数组 | 8 | 0~18446744073709551615 | 缺少相应的运算函数 |
| real32_s | 单精度实数数组 | 4 | -3.4E-38~3.4E-38 | |
| real64_s,real_s | 双精度实数数组 | 8 | -1.7E-308~1.7E-308 | |
| complex_s | 复数数组 | 16 | -1.7E-308~1.7E-308 |
数组是具有相同的数据类型且拥有同一个指针标识的相关变量所组成的线性表,可以是一维或任意维数组。数组中的每个独立变量称作元素,每个元素即一个FcData简单数据。
除以上基本数据类型外,在FcData中还可用关键字“cdef”进行类定义,通过关键字“class”创建类对象,实现复杂的数据结构。
通过FcData32.dll的输出函数接口,可以向FcData添加任意复杂的数据类型,这些类型称为外部基本数据类型。
使用二级函数typedef,可以对FcData基本数据类型进行扩展,称为扩展数据类型。实际上,任何一个FcData数据具有两个数据类型属性:扩展数据类型和基本数据类型。这两个类型属性均用4字节整数进行标识。FcData扩展数据类型可简称为FcData数据类型(以后如不加特别说明,FcData数据类型即指FcData扩展数据类型),用以表示各种不同类别的数据,而基本数据类型(包括内置的和外部的基本数据类型)较少,仅表示这种数据占多少个字节。
FcData中所有的数据都是用函数new()动态申请的,申请成功时返回一个数据指针,可通过该指针对数据进行操作,使用完后用函数delete()函数进行销毁,或者用函数DeleteAllFCD()一次性销毁所有数据。FcData中的数据是安全的,不存在内存泄漏,FcData中有自动回收垃圾的机制。
FcData中可以执行严格的或不严格的类型检查,这与具体的函数特性有关。如果函数检查FcData数据的扩展数据类型符合要求才进行操作,即是进行严格的数据检查;如果函数检查FcData数据的基本数据类型符合要求就进行操作,即是进行不严格的数据检查,具体请参考函数的相关说明。在执行严格的类型检查时,有一些函数可对不同类型的数据进行相互转换,提供了很多方便。
FcData中定义的直接对数据进行计算或操作的函数较少,FcData主要向Forcal提供更加丰富的数据类型,对FcData数据的计算或操作更多地依赖其他动态库的函数进行。
约定:在实数表达式或复数表达式中,用一个实数或复数存放FcData数据指针时,FcData数据指针存放在实数或复数的前4个字节中。
记住:FcData数据是通过Forcal整数表达式实现的,Forcal整数表达式中的数据都是4字节整数。
FcData中定义的整数常量及用途如下表:
| 常 量 | 说 明 | 常 量 | 说 明 | |
| char | 定义字符 | cdef | 定义类 | |
| Uchar | 定义无符号字符 | class | 创建类对象 | |
| int16 | 定义短整数 | EndType | 数据定义结束标志 | |
| Uint16 | 定义无符号短整数 | NotDelete | 删除类对象时,不删除指定的类成员 | |
| int32,int | 定义整数 | NULL | NULL = 0 | |
| Uint32 | 定义无符号整数 | true | 逻辑真,true != 0 | |
| int64 | 定义长整数 | false | 逻辑假,false = 0 | |
| Uint64 | 定义无符号长整数 | |||
| real32 | 定义单精度实数 | |||
| real64,real | 定义双精度实数 | |||
| complex | 定义复数 | |||
| char_s,string | 定义字符数组 | |||
| Uchar_s | 定义无符号字符数组 | |||
| int16_s | 定义短整数数组 | |||
| Uint16_s | 定义无符号短整数数组 | |||
| int32_s,int_s | 定义整数数组 | |||
| Uint32_s | 定义无符号整数数组 | |||
| int64_s | 定义长整数数组 | |||
| Uint64_s | 定义无符号长整数数组 | |||
| real32_s | 定义单精度实数数组 | |||
| real64_s,real_s | 定义双精度实数数组 | |||
| complex_s | 定义复数数组 |
命名约定:如果函数的参数中有源操作数和目的操作数,当函数名中有“to”时,源操作数在前,目的操作数在后;当函数名中没有“to”时,目的操作数在前,源操作数在后。
| 函 数 | 类型 | 用 途 | 函 数 | 类型 | 用 途 | |
| new | 整数函数 | 申请FcData数据 | FCDToStr | 整数函数 | 将FcData数据转换为字符串 | |
| delete | 整数函数 | 销毁FcData数据 | StrToFCD | 整数函数 | 将字符串转换为FcData数据 | |
| DeleteAllFCD | 整数函数 | 销毁所有FcData数据 | OutStr | 整数函数、实数函数 | 输出FcData字符数组 | |
| nDeleteAllFCD | 整数函数 | 得到销毁所有FcData数据的次数 | OutNStr | 整数函数、实数函数 | 输出Forcal近程静态字符串 | |
| NowFcDataNum | 整数函数 | 返回当前FcData数据的数目 | OutFStr | 整数函数、实数函数 | 输出Forcal远程静态字符串 | |
| get | 整数函数 | 得到一个FcData数据的值 | copy | 整数函数 | 复制FcData数据 | |
| set | 整数函数 | 设置一个FcData数据的值 | GetFCDLen | 整数函数 | 得到FcData(数组)数据长度 | |
| SetFcDataMax | 整数函数 | 设置允许申请的FcData数据的最大数 | FCDstrlen | 整数函数 | 得到字符串长度 | |
| GetCM | 整数函数 | 得到类成员指针或属性 | FCDstrcpy | 整数函数 | 复制字符串 | |
| SetCM | 整数函数 | 为类成员设置一个新指针或新属性 | FCDstrcat | 整数函数 | 连接字符串 | |
| DCM | 整数函数 | 得到基类成员指针,深度优先 | FCDstrcmp | 整数函数 | 比较字符串 | |
| BCM | 整数函数 | 得到基类成员指针,广度优先 | Asc | 整数函数 | 将字符转换成整数 | |
| GetFcDataType | 整数函数 | 得到FcData数据的类型 | delete(pFCD) | 实数函数、复数函数 | 销毁FcData数据,pFCD的前4个字节存放FcData数据指针 | |
| typedef | 整数函数 | 定义扩展数据类型 | IsPointer(p) | 实数函数、复数函数 | 判断指针p是否有效,实数(复数)中用前4个字节存放一个指针 | |
| call | 整数函数 | 动态调用表达式 |
[返回本类函数列表] [返回页首] 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,...:初始化参数。如果是数组类型,参数按最低存储地址到最高存储地址顺序存放,多余的参数将被忽略。char和char_s(string)类型参数用字符串"abc..."赋初值。如果将一个多字节数(例如大整数)赋给一个少字节数(例如小整数),数据将被截断。如果一个Type类型数据大于4个字节,则每个数据占用多个参数,即连续的多个参数组合为一个Type类型数据,占用参数的个数,取决于一个Type类型数据的长度。
说明:FcData中所有的数据都用函数new()动态申请。申请成功返回一个指向数据的指针,可通过该指针操作参数;申请失败返回0。
通过函数new()可以申请的数据类型及举例见下表。
| Type | 申请的数据 | 简单例子 | 简单例子说明 | 赋初值的例子 | 赋初值的例子说明 |
| char | 字符 | new(char) | 申请一个字符。 | new(char,"a") | 申请一个字符并赋初值为"a"。 |
| Uchar | 无符号字符 | new(Uchar) | 申请一个无符号字符。 | new(Uchar,66) | 申请一个字符并赋初值为66,66为该字符的ASCII代码。 |
| int16 | 短整数 | new(int16) | 申请一个短整数。 | new(int16,166) | 申请一个短整数并赋初值为166。 |
| Uint16 | 无符号短整数 | new(Uint16) | 申请一个无符号短整数。 | new(Uint16,166) | 申请一个无符号短整数并赋初值为166。 |
| int32,int | 整数 | new(int32) | 申请一个整数。 | new(int32,166888) | 申请一个整数并赋初值为166888。 |
| Uint32 | 无符号整数 | new(Uint32) | 申请一个无符号整数。 | new(Uint32,166888) | 申请一个无符号整数并赋初值为166888。 |
| int64 | 长整数 | new(int64) | 申请一个长整数。 | new(int64,166888,12) | 申请一个长整数并赋初值为(166888,12),两个4字节整数组合成为一个8字节长整数。 |
| Uint64 | 无符号长整数 | new(Uint64) | 申请一个无符号长整数。 | new(Uint64,166888,12) | 申请一个无符号长整数并赋初值为(166888,12),两个4字节整数组合成为一个8字节无符号长整数。 |
| real32 | 单精度实数 | new(real32) | 申请一个单精度实数。 | new(real32,166888) | 申请一个单精度实数并赋初值为166888,该数要按单精度实数规则进行解释。 |
| real64,real | 双精度实数 | new(real64) | 申请一个双精度实数。 | new(real64,166888,12) | 申请一个双精度实数并赋初值为(166888,12),这两个数共8个字节,按双精度实数规则进行解释。 |
| complex | 复数 | new(complex) | 申请一个复数。 | new(complex,16,68,88,12) | 申请一个复数并赋初值为(16,68,88,12),这四个数共16个字节,按复数规则进行解释:前2个参数组合成复数的实部,后两个参数组合成复数的虚部。 |
| char_s,string | 字符数组 | new(char_s,5) | 申请一个一维字符数组,长度为5。EndType为数据定义结束标志,下同。 | new(char_s,EndType,"abc") | 申请一个一维字符数组并赋初值为"abc",长度为字符串长度。 |
| new(char_s,5,EndType) | new(char_s,5,EndType,"abc") | 申请一个一维字符数组并赋初值为"abc",长度为5。 | |||
| new(char_s,2,3) | 申请一个二维字符数组,长度为6。 | new(char_s,2,3,EndType,"abc") | 申请一个二维字符数组并赋初值为"abc",长度为6。 | ||
| new(char_s,2,3,EndType) | |||||
| Uchar_s | 无符号字符数组 | new(Uchar_s,5) | 申请一个一维无符号字符数组,长度为5。 | new(Uchar_s,EndType,66,67,68) | 申请一个一维无符号字符数组并赋初值为(66,67,68),长度为初值数目。 |
| new(Uchar_s,5,EndType) | new(Uchar_s,5,EndType,66,67,68) | 申请一个一维无符号字符数组并赋初值为(66,67,68),长度为5。 | |||
| new(Uchar_s,2,3,5) | 申请一个三维字符数组,长度为30。 | new(Uchar_s,2,3,5,EndType,66,67,68,69,70) | 申请一个三维无符号字符数组并赋初值为(66,67,68,69,70),长度为30。 | ||
| new(Uchar_s,2,3,5,EndType) | |||||
| int16_s | 短整数数组 | new(int16_s,5) | 申请一个一维短整数数组,长度为5。 | new(int16_s,EndType,66,67,68) | 申请一个一维短整数数组并赋初值为(66,67,68),长度为初值数目。 |
| new(int16_s,5,EndType) | new(int16_s,5,EndType,66,67,68) | 申请一个一维短整数数组并赋初值为(66,67,68),长度为5。 | |||
| new(int16_s,2,3,5,2) | 申请一个四维短整数数组,长度为60。 | new(int16_s,2,3,5,2,EndType,66,67,68,69,70) | 申请一个四维短整数数组并赋初值为(66,67,68,69,70),长度为60。 | ||
| new(int16_s,2,3,5,2,EndType) | |||||
| Uint16_s | 无符号短整数数组 | new(Uint16_s,5) | 申请一个一维无符号短整数数组,长度为5。 | new(Uint16_s,EndType,66,67,68) | 申请一个一维无符号短整数数组并赋初值为(66,67,68),长度为初值数目。 |
| new(Uint16_s,5,EndType) | new(Uint16_s,5,EndType,66,67,68) | 申请一个一维无符号短整数数组并赋初值为(66,67,68),长度为5。 | |||
| new(Uint16_s,2,3,5) | 申请一个三维无符号短整数数组,长度为30。 | new(Uint16_s,2,3,5,EndType,66,67,68,69,70) | 申请一个三维无符号短整数数组并赋初值为(66,67,68,69,70),长度为30。 | ||
| new(Uint16_s,2,3,5,EndType) | |||||
| int32_s,int_s | 整数数组 | new(int32_s,5) | 申请一个一维整数数组,长度为5。 | new(int32_s,EndType,66,67,68) | 申请一个一维整数数组并赋初值为(66,67,68),长度为初值数目。 |
| new(int32_s,5,EndType) | new(int32_s,5,EndType,66,67,68) | 申请一个一维整数数组并赋初值为(66,67,68),长度为5。 | |||
| new(int32_s,2,3,5) | 申请一个三维整数数组,长度为30。 | new(int32_s,2,3,5,EndType,66,67,68,69,70) | 申请一个三维整数数组并赋初值为(66,67,68,69,70),长度为30。 | ||
| new(int32_s,2,3,5,EndType) | |||||
| Uint32_s | 无符号整数数组 | new(Uint32_s,5) | 申请一个一维无符号整数数组,长度为5。 | new(Uint32_s,EndType,66,67,68) | 申请一个一维无符号整数数组并赋初值为(66,67,68),长度为初值数目。 |
| new(Uint32_s,5,EndType) | new(Uint32_s,5,EndType,66,67,68) | 申请一个一维无符号整数数组并赋初值为(66,67,68),长度为5。 | |||
| new(Uint32_s,2,3,5) | 申请一个三维无符号整数数组,长度为30。 | new(Uint32_s,2,3,5,EndType,66,67,68,69,70) | 申请一个三维无符号整数数组并赋初值为(66,67,68,69,70),长度为30。 | ||
| new(Uint32_s,2,3,5,EndType) | |||||
| int64_s | 长整数数组 | new(int64_s,5) | 申请一个一维长整数数组,长度为5。 | new(int64_s,EndType,66,67,68,69) | 申请一个一维长整数数组并赋初值为(66,67,68,69),长度为初值数目/2 ,两个4字节整数组合成为一个8字节长整数,此例中有两个长整数。 |
| new(int64_s,5,EndType) | new(int64_s,5,EndType,66,67,68,69) | 申请一个一维长整数数组并赋初值为(66,67,68,69),长度为5,两个4字节整数组合成为一个8字节长整数。 | |||
| new(int64_s,2,3,5) | 申请一个三维长整数数组,长度为30。 | new(int64_s,2,3,5,EndType,66,67,68,69,70,71) | 申请一个三维长整数数组并赋初值为(66,67,68,69,70,71),长度为30,两个4字节整数组合成为一个8字节长整数。 | ||
| new(int64_s,2,3,5,EndType) | |||||
| Uint64_s | 无符号长整数数组 | new(Uint64_s,5) | 申请一个一维无符号长整数数组,长度为5。 | new(Uint64_s,EndType,66,67,68,69) | 申请一个一维无符号长整数数组并赋初值为(66,67,68,69),长度为初值数目/2 ,两个4字节整数组合成为一个8字节长整数,此例中有两个长整数。 |
| new(Uint64_s,5,EndType) | new(Uint64_s,5,EndType,66,67,68,69) | 申请一个一维无符号长整数数组并赋初值为(66,67,68,69),长度为5,两个4字节整数组合成为一个8字节长整数。 | |||
| new(Uint64_s,2,3,5) | 申请一个三维无符号长整数数组,长度为30。 | new(Uint64_s,2,3,5,EndType,66,67,68,69,70,71) | 申请一个三维单精度实数数组并赋初值为(66,67,68,69,70,71),长度为30,两个4字节整数组合成为一个8字节长整数。 | ||
| 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),长度为初值数目,所有数值按单精度实数规则进行解释。 |
| 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),长度为初值数目/2 ,所有数值按双精度实数规则进行解释,此例中有四个双精度实数。 |
| 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),长度为初值数目/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) | |||||
| cdef | 类 | new(cdef,"a","b","999") | 定义一个类,有三个类成员"a","b"和"999", 类成员的类型在申请类对象并进行赋值时确定,类成员的类型可以是一个类对象 。类的详细说明请参考“类”。 | ||
| class | 类对象 | new{class,DC} | 申请一个类对象,DC是预定义的类指针。类的对象成员通过函数SetCM()设置。类对象的详细说明请参考“类”。 | new{class,DC,"a",new(int,252),"b",Cvirtual,NotDelete,"999",NULL} | 申请一个类对象并赋初值,DC是预定义的类指针。给类对象赋值的顺序是任意的。类对象成员的指针可通过函数GetCM()获得。在本例中,给成员"a"赋初值为new(int,252);给成员"b"赋初值为Cvirtual,Cvirtual是预先申请的FcData数据,关键字NotDelete指出,删除该类对象时,不删除Cvirtual;给成员"999"赋初值为NULL。类对象的详细说明请参考“类”。 |
| 其他类型OtherType | 其他模块向FcData注册的数据类型 | new(OtherType) | 申请一个其他模块向FcData注册的数据,数据类型为OtherType。OtherType由其他模块定义。 | ||
[例子]
[返回本类函数列表] [返回页首] delete(pData):销毁FcData数据
pData:由函数new()返回的FcData数据指针。
说明:FcData数据用完后应及时用该函数销毁,释放数据所占据的空间。
[例子]
[返回本类函数列表] [返回页首] DeleteAllFCD():销毁所有FcData数据
[返回本类函数列表] [返回页首] nDeleteAllFCD():获得销毁所有FcData数据的次数
说明:比较在不同时刻执行该函数的返回值,可确定是否销毁了所有的FcData数据。若两次执行的返回值相等,没有销毁所有的FcData数据,若不相等,销毁了所有的FcData数据。
[返回本类函数列表] [返回页首] NowFcDataNum(n):返回当前FcData数据的数目
n:显示当前有效的FcData数据指针的最大数目。
说明:该函数可用来检查有哪些数据没有及时释放。
[返回本类函数列表] [返回页首] 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"决定的数据长度不超过4个字节,使用一个参数返回数据的值;否则参数的个数×4应等于一个该类型数据所占字节数。这些参数可以缺省。
返回值:如果pData:"a","b",...,"x"决定的数据长度不超过4个字节,直接返回数据的值,否则返回将数据截断后的值。
[例子]
[返回本类函数列表] [返回页首] 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"决定的数据长度不超过4个字节,使用一个参数设置数据的值;否则参数的个数×4应等于一个该类型数据所占字节数。
返回值:0。
[例子]
[返回本类函数列表] [返回页首] SetFcDataMax(n):设置允许申请的FcData数据的最大数
说明:缺省的FcData数据个数最大值为10000。该函数避免了在无限循环中申请数据导致的内存耗损。
FcData内部有一个计数器,每当用函数new()申请一个FcData数据,计数器就增1,但用函数delete()销毁数据时,计数器并不减1,这样当计数器达到设定的最大值时,就不能再申请数据了。不过,调用函数NowFcDataNum()可以使计数器的计数准确,只要及时用函数delete()销毁了不用的数据,就可以不断地用函数new()申请新数据。由于函数NowFcDataNum()运行较慢,一般仅在程序的开头或结尾执行一次。
[返回本类函数列表] [返回页首] GetCM(pData:"a","b",... ...,"x",bPointer):得到类成员指针或属性
pData:FcData类对象指针。
"a","b",... ...,"x":该项指出pData的对象成员。"x"可以是任意的对象成员,其余的对象成员都必须是类。
bPointer:bPointer=true:得到类成员指针;bPointer=false:得到类成员删除属性。若类成员删除属性为true,销毁类之前将销毁该类成员,否则不销毁类成员。
[例子]
[返回本类函数列表] [返回页首] SetCM(pData:"a","b",... ...,"x":p,bPointer):为类成员设置一个新指针或新属性
pData:FcData类对象指针。
"a","b",... ...,"x":该项指出pData的对象成员。"x"可以是任意的对象成员,其余的对象成员都必须是类。
p:FcData数据指针,或者类成员删除属性,取决于bPointer的值。
bPointer:bPointer=true:设置类成员指针;bPointer=false:设置类成员删除属性。若类成员删除属性为true,销毁类之前将销毁该类成员,否则不销毁类成员。
[例子]
[返回本类函数列表] [返回页首] DCM(pData,"a"):得到基类成员指针,深度优先
pData:FcData类对象指针。
"a":该项指出pData的对象成员。"a"可以是一个基类的对象成员。
说明:该函数先在FcData的成员中寻找"a",若找不到,就会到该类的基类(父类)中寻找。如果有多个基类,则搜索按照基类(base class)在类定义中的顺序从左至右,深度优先,返回第一个找到的值。
[例子]
[返回本类函数列表] [返回页首] BCM(pData,"a"):得到基类成员指针,广度优先
pData:FcData类对象指针。
"a":该项指出pData的对象成员。"a"可以是一个基类的对象成员。
说明:该函数先在FcData的成员中寻找"a",若找不到,就会到该类的基类(父类)中寻找。如果有多个基类,则搜索按照基类(base class)在类定义中的顺序从左至右,广度优先,返回第一个找到的值。
[例子]
[返回本类函数列表] [返回页首] GetFcDataType(pData,&BasicType):得到FcData数据的类型
pData:FcData数据指针。
BasicType:返回FcData基本数据类型。
[返回本类函数列表] [返回页首] 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);
[返回本类函数列表] [返回页首] call(ForType,ForHandle : x0,x1,x2,... : &r0,...):动态调用表达式
ForType,ForHandle:表达式的类型及句柄。ForType=1表示整数表达式,ForType=2表示实数表达式,ForType=3表示复数表达式。
x0,x1,x2,...:表达式参数。调用整数表达式时,参数个数与表达式参数个数相同;调用实数表达式时,参数个数为表达式参数个数的2倍;调用复数表达式时,参数个数为表达式参数个数的4倍。
&r0,...:表达式的返回值。ForType=1时只有&r0;ForType=2时为&r0,&r1;ForType=3时为&r0,&r1,&r1,&r2。必须使用引用参数。
说明:表达式调用成功时返回1,否则返回0。
[例子]
i:a(x)= x=x+1;
b(x)= x=x+1;
c:c(x)= x=x+1+i;
i:(:y)= call[1,HFor("a",1):11:&y],y;
i:(:a,b,c,d,s)= s=new[char_s,80,EndType:"22"],StrToFCD[s,real:&a,&b],call[2,HFor("b",2):a,b:&c,&d],FCDToStr[real:c,d:s],OutNStr["/013/010结果:"],OutStr[s];
i:(:a,b,c,d,e,f,g,h,s)=
{
s=new[char_s,80,EndType:"2-2i"], //申请一个字符串,存放一个复数
StrToFCD[s,complex:&a,&b,&c,&d], //将复数转换并保存到a,b,c,d
call[3,HFor("c",3):a,b,c,d:&e,&f,&g,&h], //调用复数表达式c,返回值保存到e,f,g,h
FCDToStr[complex:e,f,g,h:s], //将复数a,b,c,d转换为字符串并保存到s
OutNStr["/013/010结果:"],OutStr[s] //输出字符串s
};
[返回本类函数列表] [返回页首] FCDToStr(Type:x0,x1,x2,...:pChar_s)或FCDToStr(pFCD,pChar_s):将FcData数据转换为字符串
Type:FcData数据类型,只能是简单数据类型。Type不能为数组,也不能为类及类对象。
x0,x1,x2,...:数据。如果Type类型数据的字节数大于4,则数据个数×4等于该数据类型的字节长度。
pChar_s:字符数组指针。
pFCD:FcData数据指针,只能是简单数据类型。pFCD不能为数组,也不能为类及类对象。
[例子1] i:(:a,b)= a=new[real,2,3],b=new[char_s,80],FCDToStr[a,b],b.OutStr[];
[例子2]
[返回本类函数列表] [返回页首] StrToFCD(pChar_s,Type:x0,x1,x2,...)或StrToFCD(pChar_s,pFCD):将字符串转换为FcData数据
pChar_s:字符数组指针。注意:数字字符(包括符合、小数点等有效字符)必须是连续的,否则转换结果不正确。例如:不要将“-6.5e-9”写成“- 6.5e-9”。但数字前后空格不影响转换结果。
Type:FcData数据类型,只能是简单数据类型。Type不能为数组,也不能为类及类对象。
x0,x1,x2,...:数据。如果Type类型数据的字节数大于4,则数据个数×4等于该数据类型的字节长度。
pFCD:FcData数据指针,只能是简单数据类型。pFCD不能为数组,也不能为类及类对象。
[例子1] i:(:s,a,b,j,k,h,g)=s=new[char_s,EndType:"-6.5e-9 -6e-5i"],a=new[complex],b=new[char_s,80],StrToFCD[s,complex:&j,&k,&h,&g],FCDToStr[complex:j,k,h,g:b],b.OutStr[];
[例子2]
[返回本类函数列表] [返回页首] OutStr(pStr):输出FcData字符数组
pStr:FcData字符数组指针。
[例子]
[返回本类函数列表] [返回页首] OutNStr("hello!"):输出Forcal近程静态字符串
[返回本类函数列表] [返回页首] OutFStr(ForType,ForHandle,"hello!"):输出Forcal远程静态字符串
ForType,ForHandle:表达式的类型及句柄。ForType=1表示整数表达式,ForType=2表示实数表达式,ForType=3表示复数表达式。
[例子]
a()="hello !";
OutFStr[2,HFor("a",2),a()];
i: OutFStr[2,HFor("a",2),a()];
[返回本类函数列表] [返回页首] copy(dest,source,bSame):复制FcData数据
dest:FcData目的数据指针。
source:FcData源数据指针。
bSame:当bSame=true时,dest和source的数据类型完全相同才进行复制;当bSame=false时,dest和source的类型不必完全相同,只要数据元素的字节数相同就可进行复制。若缺省该参数,相当于bSame=true。
说明:将源数据复制到目的数据。如果进行类对象的复制,要求类对象有相同的数据结构,但bSame=false时,类成员不必严格匹配。
[例子1] i:(:a,b)= a=new[char_s,80,EndType:"hello FcData!"],b=new[char_s,80],copy[b,a],b.OutStr[];
[例子2] i:(:a,b)= a=new[int16,-823],b=new[Uint16],copy[b,a,false],b.get[];
[例子3] 简单的类对象复制
i:a(::ab) = ab=new[cdef,"a","b"]; //类定义,有两个类成员 i:b(::a,b,ab) = a=new{class,ab:"a",new[int,89]:"b",new[char_s,80,EndType,"hello FcData!"]}, //申请ab类型的类对象并给类成员赋初值 b=new{class,ab:"a",new[int]:"b",new[char_s,80]}; //申请ab类型的类对象,但类成员没有赋初值 i:c(::a,b) = copy[b,a]; //复制类对象 i:d(::b) = b."a".get[]; //获得类对象b的类成员"a"的值 i:e(::b) = b."b".GetCM(true).OutStr[]; //获得类对象b的类成员"b"的值
[例子4] 复杂的类对象复制
i:a(::Ca) = Ca=new[cdef,"a"]; //类定义,有一个类成员 i:b(::Cabc) = Cabc=new[cdef,"a","b","c"]; //类定义,有三个类成员 i:c(::a,b,Ca,Cabc) = a=new{class,Cabc: //申请Cabc类型的类对象并给类成员赋初值,嵌套了类Ca "a",new[int,89], "b",new[char_s,80,EndType,"hello FcData!"], "c",new{class,Ca: "a",new[int,-789] } }, b=new{class,Cabc: //申请Cabc类型的类对象,但类成员没有赋初值,嵌套了类Ca "a",new[int], "b",new[char_s,80], "c",new{class,Ca: "a",new[int] } }; i:d(::a,b) = copy[b,a]; //复制类对象 i:e(::b) = b."a".get[]; //获得类对象b的类成员"a"的值 i:f(::b) = b."b".GetCM(true).OutStr[]; //获得类对象b的类成员"b"的值 i:g(::b) = b."c"."a".get[]; //获得类对象b的基类成员"c"的类成员"a"的值
[返回本类函数列表] [返回页首] GetFCDLen(pFCD):得到FcData(数组)数据长度
pFCD:FcData数据指针。
返回值:如果pFCD是简单数据返回0;如果pFCD是数组数据返回数组长度;其他情况返回-1。
[返回本类函数列表] [返回页首] FCDstrlen(pStr)或FCDstrlen("hello!",x)或FCDstrlen(ForType,ForHandle,"hello!"):得到字符串长度
pStr:FcData字符数组指针。
x:任意值。
ForType,ForHandle:表达式的类型及句柄。ForType=1表示整数表达式,ForType=2表示实数表达式,ForType=3表示复数表达式。
说明1:OutStr有一个参数时,获得FcData字符串长度;OutStr有二个参数时,获得Forcal近程静态字符串长度;OutStr有三个参数时,获得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表示复数表达式。
说明:OutStr有2个参数时,复制FcData字符串到目的字符串;OutStr有3个参数时,复制Forcal近程静态字符串到目的字符串;OutStr有4个参数时,复制Forcal远程静态字符串到目的字符串。
[例子1] i:(::a)= a=new[char_s,20,EndType,"Hello"],FCDstrcpy[a," FcData!",0],a.OutStr[];
[例子2] i:(::a,b)= a=new[char_s,80,EndType,"Hello"],b=new[char_s,EndType," FcData!"],FCDstrcpy[a,b],a.OutStr[];
[返回本类函数列表] [返回页首] 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:OutStr有2个参数时,连接FcData字符串到目的字符串;OutStr有3个参数时,连接Forcal近程静态字符串到目的字符串;OutStr有4个参数时,连接Forcal远程静态字符串到目的字符串。
说明2:将源字符串连接到目的字符串dest的后面。
[例子1] i:(::a)= a=new[char_s,20,EndType,"Hello"],FCDstrcat[a," FcData!",0],OutStr[a];
[例子2] i:(::a,b)= a=new[char_s,80,EndType,"Hello"],b=new[char_s,EndType," FcData!"],FCDstrcat[a,b],OutStr[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表示复数表达式。
说明:OutStr有2个参数时,与FcData字符串进行比较;OutStr有3个参数时,与Forcal近程静态字符串进行比较;OutStr有4个参数时,与Forcal远程静态字符串进行比较。
返回值:字符串相等时返回0,否则返回非0值。
[例子1] i:(::a)= a=new[char_s,EndType,"FcData"],FCDstrcmp[a,"FcData",0];
[例子2] i:(::a)= a=new[char_s,EndType,"FcData"],FCDstrcmp[a,"fcdata",0];
[例子3] i:(::a,b)= a=new[char_s,EndType,"FcData"],b=new[char_s,EndType,"FcData"],FCDstrcmp[a,b];
[返回本类函数列表] [返回页首] Asc("a")或Asc(k):将字符转换成整数
k:Forcal内置字符串指针。
说明:如果字符串包含多个字符,则仅将第一个字符转换成整数。
[例子1] i: Asc("a"); //将字符“a”转换成整数
[例子2] i: Asc("abc"+1); //将字符“b”转换成整数
[例子3] i: (:k)= k="abc", Asc(k); //将字符“a”转换成整数
4.1 类
除了FcData固有的基本数据类型外,用户还可以通过类定义自己的数据类型。类是一种组合型数据类型,它一般由一个或多个成员组成,形成一个独立的逻辑单元。与数组不同的是,类中的成员可以是不同的数据类型。
要使用类,必须先定义它的形式。类的定义通过函数new(cdef,"a","b",... ...)来完成。关键字cdef说明要定义一个类。字符串"a","b",... ...定义了类的成员,每一个字符串标识一个类成员,区分大小写。注意类成员名称不要重复,否则后定义的类成员将无法访问。在类定义时无法确定类成员的类型,类成员的类型在申请类对象并进行赋值时确定,类成员的类型可以是一个类对象。
定义完类后,可以通过函数new(class,DC:"a",x:"b",y,NotDelete:... ...)创建类的对象(或变量)。关键字class说明要创建一个类对象。DC是预定义的类指针,根据该类定义创建类的成员。在创建类时可以给类成员赋值,赋值的顺序是任意的。本例中,给成员"a"赋初值为x;给成员"b"赋初值为y,关键字NotDelete指出,删除该类对象时,不删除y。一般情况下,x和y都是FcData数据指针,当然也可以是任意的整数。
每一个类成员都有删除属性,如果属性为true,在销毁类对象时,将先销毁该类成员,如果属性为false,将不销毁该类成员。在创建类对象时,类成员的删除属性缺省情况下为true,但可以用关键字NotDelete指明该类成员的删除属性为false。对于已经存在的类对象,可以用函数GetCM()和SetCM()获得或设置类成员及属性。
一般情况下,类成员是一个FcData数据指针,类成员的类型即FcData数据类型。FcData数据可以用函数set()获得,用函数set()进行设置,而数据指针用函数GetCM()获得,用函数SetCM()进行设置。当然,也可以将数据指针本身当作数据,而不管数据指针是否有效,实际上,数据指针就是一个4字节整数。
一个类至少要有一个类成员。FcData规定类的第一个成员作为该类的名称。但类的名称不是该类的唯一标识,类的唯一标识是类指针。FcData允许多个类的名称相同,为了区分不同的类,要为每个类起一个不同的名字。FcData甚至允许多个完全相同的类定义同时存在,除非特殊需要,在实际应用中应避免出现这种情况。
注意:不要在销毁类对象之前销毁类的定义,这可能导致类对象成员的解释出错,但这也是极为罕见的。
如果类A是类B的对象成员,则称类A为类B的基类(父类),类B为类A的派生类(子类)。类可以多重继承,也可以形成循环链表互为基类或派生类。可以用函数DCM()或BCM()获得基类的对象成员,这两个函数搜索基类对象成员的方法不同,DCM()是深度优先的,而BCM()广度优先。
对每一种特定的类对象,都设计一个专门的函数来创建它,这样容易实现类的继承。
设计一个模块,专门用来处理有特定意义的类,这样的模块称为类模块。通过模块变量、模块的私有函数(仅模块内使用的表达式),可以实现对数据处理的封装和隐藏,通过模块的公有函数(可供其他模块调用的表达式),可以输出模块的功能。
以下函数在类的操作中是常用的:
(1)获得类成员的值:pData."a"."b"..."x".get(n1,n2,...,nm:&x0,&x1,&x2,...);
(2)给类成员赋值:pData."a"."b"..."x".set(n1,n2,...,nm:x0,x1,x2,...);
(3)得到类成员指针或属性:pData."a"."b"... ..."x".GetCM(bPointer)
(4)为类成员设置一个新指针或新属性:pData."a"."b"... ..."x".SetCM(p,bPointer);
(5)得到基类成员指针(深度优先):pData.DCM("a");
(6)得到基类成员指针(广度优先):pData.BCM("a");
下面的类定义给出了一个人的简单信息:
Cperson=new(cdef:"姓名","性别","年龄");
申请一个类对象:
person=new(class,Cperson);
给类对象赋值:
person."姓名".SetCM[new(char_s,EndType,"王强"),true];
person."性别".SetCM[new(char_s,EndType,"男"),true];
person."年龄".SetCM[new(int,23),true];
也可以在申请类对象时直接赋值:
person=new{class,Cperson:
"姓名",new(char_s,EndType,"王强"),
"性别",new(char_s,EndType,"男"),
"年龄",new(int,23)
};
获得并输出类对象的值:
OutStr[person."姓名".GetCM(true)];
OutStr[person."性别".GetCM(true)];
person."年龄".get();
以下是一些类的使用的例子:
例子1:申请类对象并赋初值
i:a(::ab) = ab=new[cdef:"a","b"]; //类定义,有两个类成员
i:b(::a,ab) = a=new{class,ab: //申请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,ab) = delete[a],delete[ab]; //删除类对象a及类定义ab
例子2:申请类对象并通过SetCM()赋值
i:a(::ab) = ab=new[cdef:"a","b"]; //类定义,有两个类成员 i:b(::a,ab) = a=new(class,ab); //申请ab类型的类对象 i:c(::a) = a."a".SetCM[new(int,89),true], //给类成员"a"赋值为整数89 a."b".SetCM[new(int,-1289),true]; //给类成员"b"赋值为整数-1289 i:d(::a) = a."a".GetCM[true]; //得到类成员"a"的指针 i:e(::a) = a."a".get[]; //获得类成员"a"的值 i:f(::a) = a."b".GetCM[true]; //得到类成员"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,ab) = delete[a],delete[ab]; //删除类对象a及类定义ab
例子3:循环链表及删除方法1
i:a(::ab) = ab=new[cdef:"a","b"]; //类定义,有两个类成员 i:b(::a,b,ab) = a=new{class,ab:"a",new[int,89]}, //申请ab类型的类对象a并赋初值为整数89 b=new{class,ab:"a",new[int,-89]}; //申请ab类型的类对象b并赋初值为整数-89 i:c(::a,b) = a."b".SetCM[b,true]; //让类对象a的类成员"b"指向类对象b i:d(::a,b) = b."b".SetCM[a,true]; //让类对象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,ab) = delete[a],delete[ab]; //删除类对象a、b及类定义ab
例子4:循环链表及删除方法2
i:a(::ab) = ab=new[cdef:"a","b"]; //类定义,有两个类成员 i:b(::a,b,ab) = a=new{class,ab:"a",new[int,89]}, //申请ab类型的类对象a并赋初值为整数89 b=new{class,ab:"a",new[int,-89]}; //申请ab类型的类对象b并赋初值为整数-89 i:c(::a,b) = a."b".SetCM[b,true]; //让类对象a的类成员"b"指向类对象b i:cc(::a,b) = a."b".SetCM[false,false]; //让类对象a的类成员"b"不能自动删除 i:d(::a,b) = b."b".SetCM[a,true]; //让类对象b的类成员"b"指向类对象a i:dd(::a,b) = b."b".SetCM[false,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,ab) = delete[a],delete[ab]; //删除类对象a及类定义ab,类对象b没有删除 i:k(::b) = delete[b]; //删除类对象b
例子5:给任意字符串创建单链表,并按字符从小到大排序
i:a(::str) = str=new[char_s,EndType:"q8 af580f b"]; //定义任意字符串 i:b(::Cstr) = Cstr=new[cdef:"ch","pnext"]; //类定义,有两个类成员 i:c(::head,Cstr) = head=new{class,Cstr:"ch",new(Uchar,0),"pnext",NULL}; //申请头结点,存储最小字符代码0 i:d(:i,ch,p,pStr:head,Cstr,str) = i=0,pStr=head,while{1, //按字符串创建链表 ch=str.get(i), p=new{class,Cstr:"ch",new(Uchar,ch):"pnext",NULL}, pStr."pnext".SetCM[p,true], 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".GetCM[true], //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".GetCM[true] }, if(!bEx,break()), end=pp }; i:f(:str80,p:head) = str80=new[char_s,80], //输出排序后的字符 p=head."pnext".GetCM[true], while{p, FCDToStr[char,get(p,"ch"),str80],str80.OutStr[], p=p."pnext".GetCM[true] }, delete[str80]; i:j(::head,Cstr,str) = delete[head],delete[Cstr],delete[str]; //删除类对象、类定义及字符串
例子6:类的继承
以下类的继承实现了如下类层次关系。
"c":a-->"a":11
|
"e":cd-->|
| |
| "d":44
ef-->|
| "a":22
| |
"f":ab-->|
|
"b":33
i:a(::A) = A=new[cdef:"a"]; //类定义,有一个类成员
i:b(::AB) = AB=new[cdef:"a","b"]; //类定义,有两个类成员
i:c(::CD) = CD=new[cdef:"c","d"]; //类定义,有两个类成员
i:d(::EF) = EF=new[cdef:"e","f"]; //类定义,有两个类成员
i:e(::a,ab,cd,ef,A,AB,CD,EF) =
{ a=new{class,A,"a":new(int,11)},//申请A类型的类对象并赋初值
ab=new{class,AB,"a":new(int,22),"b":new(int,33)}, //申请AB类型的类对象并赋初值
cd=new{class,CD,"c":a,"d":new(int,44)},//申请CD类型的类对象并赋初值
ef=new{class,EF,"e":cd,"f":ab} //申请EF类型的类对象并赋初值
};
i:f(::ef) = ef.DCM("a").get[];//深度优先,获得间接基类成员a-->"a":11
i:g(::ef) = ef.BCM("a").get[];//广度优先,获得直接基类成员ab-->"a":22
i:h(::ef,A,AB,CD,EF) = delete[ef],delete[A],delete[AB],delete[CD],delete[EF]; //删除类对象ef及类定义A、AB、CD、EF
4.2 Forcal和FcData中类的特点
所有的面向对象语言(OOP语言)都具有三个共同的特征:封装性、多态性和继承性。OOP语言中的类一般有公有数据、私有数据、公有函数和私有函数。在类的外部无法访问类的私有数据,也无法调用类的私有函数。在一般的语言中,类的公有数据、私有数据、公有函数和私有函数都需要在类的定义中说明。如果是静态语言,编译器将在编译时检查源代码中类的成员使用是否合法,若不合法将给出错误信息;在动态语言中,一般在运行时进行这项检查,若不合法,也将给出错误信息。有些高级语言如C++,通过运算符重载和函数重载实现编译时的多态性,通过虚函数实现运行时的多态性。
Forcal实现了面向对象的大多数特征,但与一般的语言相比,也有一些重要的区别。在Forcal中,任何一个数据都可以看作是一个对象,任何一个函数都可以看作是对象的成员函数。对象能否被函数处理,需要在运行时才能确定,若不能处理,将给出运行错误。Forcal未将函数绑定到类的说明中,似乎不符合类的常规定义,但对一个动态语言来说,这是无关紧要的。试想一下,将函数绑定到类中,运行时检查函数使用是否合法,与不将函数绑定到类中,运行时检查函数的参数使用是否合法,二者似乎没有太大差别。
Forcal中的模块,实现了对私有数据和函数的封装,模块通过输出公有函数与外界交换信息。Forcal中可实现在运行时查找运行一个已存在的函数,或者即时编译运行一个函数,支持运行时的多态性。不过,Forcal中目前不支持运算符的重载,以后也不一定增加该功能,因为重载运算符是靠定义函数实现的,使用函数完全可以完成相同的功能,在动态语言中重载运算符会使编译器变得臃肿低效。
在Forcal扩展动态库FcData中实现了类。FcData中的类是简洁高效的,类的成员都是公有数据,每一个数据可看作一个对象,所有的数据都通过特定的函数进行存取,在类中无需定义成员函数。要想使用私有数据和函数,把类放到模块(称类模块)中就可以了。FcData中的类及成员之间有自然的继承性,而且可以通过循环链表实现相互继承。FcData中的类层次关系是一棵树或一个连通图。缺省情况下,在FcData中销毁一个类对象时,所有的基类对象也一并销毁,在类对象以循环链表的方式相互继承的情况下也是这样。
5 在实数或复数表达式中使用FcData数据
根据约定,在实数表达式或复数表达式中,用一个实数或复数存放FcData数据指针时,FcData数据指针存放在实数或复数的前4个字节中。使用GetCalByte函数,有两种方法可以在实数表达式或复数表达式中申请FcData数据。
(1)调用整数表达式申请FcData数据后,紧接着执行GetCalByte函数获得FcData数据指针
i:a(x)=new(char); //参数x无意义,仅用来避免表达式被自动执行
(:y)= y=GetCalByte(a(0)); //FcData数据指针在y的前4个字节中
(2)用CalFor调用整数二级函数new申请FcData数据后,紧接着执行GetCalByte函数获得FcData数据指针
(:y)= y=GetCalByte[CalFun(4,"new",char)]; //FcData数据指针在y的前4个字节中
在实数表达式或复数表达式中,可以用函数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)对操作频繁的类成员,先用函数GetCM()、DCM()或BCM()获得类成员的指针,然后用函数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)调试时,用函数NowFcDataNum()检查有哪些数据没有及时释放,及时释放应该释放的FcData数据。
8 FcData32.dll中的输出函数 [返回页首] [返回目录]
FcData是一个标准的Forcal扩展动态库,共输出了5个函数,其中一个即标准的Forcal扩展动态库输出函数ForcalDll(...)。在加载FcData并初始化之后,也可以用SearchKey("RegFcDataType",FC_PrivateKey_User);、SearchKey("IsFcData",FC_PrivateKey_User);、SearchKey("NewFcDataArray",FC_PrivateKey_User);和SearchKey("DelFcDataArray",FC_PrivateKey_User);获得另外4个函数的句柄。输出这4个函数可使FcData能更好地用在没有指针的编程语言中,例如 VB 。这4个函数的功能和用法如下:
8.1 注册FcData数据:fcINT _stdcall RegFcDataType(int Mode,void *NewFCD,void *DeleteFCD);
说明:注册FcData数据。可注册或销毁外部基本数据类型和扩展数据类型,外部基本数据类型在销毁时必须提供删除函数,扩展数据类型可被随意销毁。
Mode=1:申请一个外部基本数据类型,NewFCD为申请该数据类型的函数指针,DeleteFCD为释放该数据类型的函数指针;申请失败时返回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数据指针。
说明:当注册新数据类型成功,在Forcal源代码中使用函数new(NewType)申请该类型数据时,FcData将调用函数NewFCD()申请新数据;当在Forcal源代码中使用函数delete(pFCD)销毁该数据时,FcData将调用函数DeleteFCD(pFCD)销毁该数据。
注意:注册FcData数据的模块必须在释放FcData之前调用RegFcDataType(0,NewFCD,DeleteFCD)注销所注册的外部基本数据类型。用RegFcDataType(2,NewFCD,DeleteFCD)模式注册的FcData数据类型可不必注销。
8.2 判断是否是FcData数据:fcINT _stdcall IsFcData(fcINT pFCD,fcINT &BasicType);
pFCD:FcData数据指针。
BasicType:返回FcData基本数据类型。
返回值:返回FcData扩展数据类型,返回0表示不是FcData数据。
说明:FcData内置数据类型是一个Forcal整数常量,可通过Forcal的输出函数ExMsgWithForcal(Key_IntConst,"char",Msg1,Msg2)查询。
8.3 申请FcData数组数据:bool _stdcall NewFcDataArray(fcINT BType,fcINT *SeedDimension,fcINT *&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(fcINT *Dimension,void *ArrayS);
Dimension:FcData数组描述指针。
ArrayS:指向数据的指针,多维数据存在一维数组中。
说明:由函数NewFcDataArray申请的FcData数组数据如果没有使用,需用该函数销毁。或者销毁被NewFcDataArray申请的FcData数组数据替换的内容。
参考:在其他模块中使用FcData数据。
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。
在其他模块(例如动态库)中访问FcData数据时,需要设计Forcal二级函数并进行注册,在Forcal二级函数中访问FcData数据。
10 通过其他模块扩展FcData数据 [返回页首] [返回目录]
(1)通过函数ExMsgWithForcal(7,void *hMsg,void *&Msg1,void *&Msg2)获得FcData向Forcal注册的数据类型标识,如char、int等。
(2)通过函数RegFcDataType(Mode,NewFCD,DeleteFCD)向FcData注册数据类型。
(3)设计并注册Forcal二级函数,通过二级函数及IsFcData(pFCD,BasicType)使用向FcData注册的数据类型,或者使用FcData基本数据类型。
(4)在释放FcData之前调用RegFcDataType(0,NewFCD,DeleteFCD)注销所注册的数据类型。
如果仅仅是使用FcData数据,则仅使用步骤(1)和(3)就可以了。
版权所有© Forcal数学软件 2008-2008,保留所有权利
E-mail: forcal@sina.com QQ:630715621
最近更新: <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%Y年%m月%d日" startspan -->2009年06月10日<!--webbot bot="Timestamp" i-checksum="1265" endspan -->
本指南介绍FcData32.DLL的使用方法,包括数据类型、函数和类等核心内容。涵盖如何在Forcal中使用FcData扩展动态库进行数据管理和操作。

被折叠的 条评论
为什么被折叠?



