首页 > 代码库 > 第五课 详解数据类型
第五课 详解数据类型
delphi中声明数据类型用关键字Var,关键字Var可以在很多地方使用,如放在函数或过程的开始部分的叫局部变量。放在单元中的叫全局变量。delphi中数据类型分为三大类:即有序数据类型,实数类型和字符类型。在细分可以分成。整数类型,布尔类型,字符类型,实数类型,日期和时间类型,自定义数据类型。等等。现在具体讲解各种类型。
其中有序数据类型,布尔类型和字符类型按取值范围划分
大小 | 有符号 | 无符号 |
8 Bits | shortInt -128 to 127 | Byte 0 to 255 |
16 bits | SmallInt -32768 to 32767 | Word 0 to 65535 |
32 bits | LongInt -2147483648 to 2147483647 | LongWord 0 to 4294967295 |
64 bits | Int64 | |
16/32 bits | Integer | Cardinal |
布尔类型
布尔值不同于布尔类型,平时很少用到。ByteBool、 WordBool 和LongBool这三种布尔类型的布尔值比较特殊,只在Windows API 函数中才用到它们。我们常用的Boolean类型,真为True值为1,假为False值为0.
字符类型
字符类型有两种表示法:ANSIchar 和WideChar,第一种类型有8位字符,它属于美国标准字符。第二种代表16位的字符,它是用Unicode字符,也就是双字节。
常量字符
常量字符可以代表用一个符号来表示如‘K’,也可以用#78,后者也可以用chr(78)表示。用Ord函数可以相反的转换Ord(k).
还有一些特殊的字符:
#9跳格(Tab键)
#10换行
#13回车(Enter键)
有序类型
说明 | 作用 |
DEC | 将参数值递减1或一个特定的值 |
inc | 将参数值增加1或一个特定的值 |
Odd | 如果参数为奇数返回真 |
Pred | 根据参数在其数据类型定义中的序列,返回参数的前驱值 |
Succ | 返回参数值的后继值 |
Ord | 返回参数在其数据类型值集合中的序号 |
Low | 返回参数对应有序数据类型的最小值 |
High | 返回参数对应有序数据类型的最大值 |
实数类型
实数类型代表不同格式的浮点数。如single类型为4个字节,Double类型为8个字节,Extended浮点类型,占10个字节。
Read类型在Delphi早期版本中占6个字节,基本现在不使用该类型。
另外还有两种奇怪的数据类型:Comp 类型和Currency 类型,Comp 类型用 8 个字节描述非常大的整数(这种类型可支持带有 18 位小数的数字);Currency 类型 (16 位版的Delphi不支持该类型) 表示一个有四位小数位的值,它的小数位长度是固定的,同Comp 类型一样也占 8 个字节。正如名字所示,Currency 数据类型是为了操作很精确的四位小数货币数值才添加的。
对实型数据,我们没办法编一个类似Range的程序,因为High 、Low及 Ord函数不能用于实型值。理论上说实型类型代表一个无限的数字集合;有序类型代表一个有限的数字集合。
注意:让我进一步把上述问题解释一下。对于整数 23,你能确定23 后面的数是什么 ,因为整型数是有限的,它们有确定的值域范围及排列顺序。而浮点数即使在一个很小的值域范围内也无限、无序。 事实上,在 23 和 24 之间有多少值? 哪个值是 23.46 后面的值? 23.47 还是 23.461,或者 23.4601? 这是很难说清的。 |
因此,如问Char 类型字符 w 的顺序位置是有意义的, 但同样的问题对浮点类型数 7134.1562 就毫无意义。对于一个实型数,你能确切知道有没有比它大的实型数,但是,如想探究给定的实数前到底有多少个实型数(这是Ord 函数的作用),是得不到结果的。
实型类型在用户界面编程中用得不多,但是Delphi从各方面支持实型类型,包括在数据库方面的支持。由于支持IEEE浮点数运算标准,Object Pascal 语言完全适合于各类数值计算编程。如果对这部分感兴趣,你可以参考Delphi 在System单元中提供的算术函数(详细见Delphi 帮助)。
日期时间类型
Delphi 也用实型数表示日期和时间数据。但为了更准确起见,Delphi 特别定义了TDateTime 数据类型,这是一个浮点类型,因为这个类型必须足够宽,使变量能容纳年、月、日、时、分和秒、甚至毫秒。日期值按天计数,从1899-12-30开始,放在TDateTime 类型的整数部分;时间值则位于十进制数的小数部分。
TDateTime 不是编译器可直接识别的预定义类型,它在System单元定义:
type TDateTime = type Double;
使用TDateTime 类型很简单,因为Delphi 为该类型定义了一系列操作函数,表3.3列出了这些函数。
例程 | 作用 |
---|---|
Now | 返回当前日期及时间 |
Date | 返回当前日期 |
Time | 返回当前时间 |
DateTimeToStr | 按缺省格式将日期和时间值转换为字符串;特定格式转换可用 FormatDateTime函数 |
DateTimeToString | 按缺省格式将日期和时间值拷贝到字符串缓冲区 |
DateToStr | 将TDateTime值的日期部分转为字符串 |
TimeToStr | 将TDateTime值的时间部分转为字符串 |
FormatDateTime | 按特定格式将日期和时间值转换为字符串 |
StrToDateTime | 将带有日期和时间信息的字符串转换为TdateTime类型值,如串有误将引发一个异常 |
StrToDate | 将带有日期信息的字符串转换为TDateTime类型格式 |
StrToTime | 将带有时间信息的字符串转换为TDateTime类型格式 |
DayOfWeek | 根据传递的日期参数计算该日期是一星期中的第几天 |
DecodeDate | 根据日期值返回年、月、日值 |
DecodeTime | 根据时间值返回时、分、秒、毫秒值 |
EncodeDate | 组合年、月、日值为TDateTime类型值 |
EncodeTime | 组合时、分、秒、毫秒值为TDateTime类型值 |
为了显示怎样使用日期时间类型及其相关例程,我建了一个简单的例子TimeNow。该例子在主窗体中设置了一个按钮和一个列表框(ListBox)。开始执行时,程序自动计算并显示当前的时间及日期,以后每次单击按钮 ,显示从程序开始至当前的时间。
下面列出了窗体的OnCreate 事件代码:
procedure TFormTimeNow.FormCreate(Sender: TObject);begin StartTime := Now; ListBox1.Items.Add (TimeToStr (StartTime)); ListBox1.Items.Add (DateToStr (StartTime)); ListBox1.Items.Add (‘Press button for elapsed time‘);end;
第一句中调用了Now 函数,这个函数返回当前的日期和时间,它的值保存在StartTime 变量中,StartTime 变量是全程变量,其声明如下:
var FormTimeNow: TFormTimeNow; StartTime: TDateTime;
我只添加了第二个声明,第一个是由Delphi自动添加的。默认情况下的代码如下:
var Form1: TForm1;
窗体名改变后,这个声明被自动更新。使用全程变量实际上不是最好的办法,更好的方法是使用窗体类的私有域,这涉及到面向对象的编程技术。
接下来的三个语句向位于窗体左面的列表框添加三个条目,结果见图3.3。列表框中的第一行显示了TDateTime 值的时间部分字符串、第二行显示的是同一值的日期部分,最后一行显示了一个简单的提示。
图 3.3:例TimeNow启动时的输出显示
当用户单击Elapsed 按钮时,上图第三行字符串被程序的计算结果代替:
procedure TFormTimeNow.ButtonElapsedClick(Sender: TObject);var StopTime: TDateTime;begin StopTime := Now; ListBox1.Items [2] := FormatDateTime (‘hh:nn:ss‘, StopTime - StartTime);end;
这串代码再次计算当前的时间,并显示当前与程序开始之时的时间差,其中用到了其它事件中的计算值,为此不得不把该值存入全程变量。实际上,最好是采用基于类的变量。
注意:上面代码中所用ListBox的索引号为2,,而它代表的是第三行的显示输出,其原因是listbox的数据项是从零开始计数的:第一项计为0,第二项为1,第三项为2,依次类推,后面涉及数组时再详细讨论这方面内容。
除了调用TimeToStr和 DateToStr 外,以上例子中还用到了功能强大的FormatDateTime 函数(关于格式化参数详见Delphi 帮助文件)。需要注意的是:当时间和日期转换成字符串时,其转换格式取决于Windows 的系统设置。Delphi 从系统中读这些值,并把它们拷贝到SysUtils 单元中声明的几个全程常量中,例如:
DateSeparator: Char;ShortDateFormat: string;LongDateFormat: string;TimeSeparator: Char;TimeAMString: string;TimePMString: string;ShortTimeFormat: string;LongTimeFormat: string;ShortMonthNames: array [1..12] of string;LongMonthNames: array [1..12] of string;ShortDayNames: array [1..7] of string;LongDayNames: array [1..7] of string;
大部分全程常量与currency 和浮点数格式化有关,在 Delphi 帮助的 Currency and date/time formatting variables 主题下,你可找到完整的清单。
注意:Delphi 中有一个DateTimePicker 控件,它提供了选择日期的常用途径,即从一个日历中选择日期。
特定的Windows 类型
到目前为止,我们所看到的预定义数据类型都是Pascal 语言自身定义的类型。 Delphi 中还包含Windows系统定义的数据类型,这些数据类型不是Pascal语言的组成部分,而是Windows 库的一部分。Windows 类型包括新增的缺省类型(例如DWORD 或UINT)、各种记录(或结构)类型及指针类型等。
Windows 定义的数据类型中,最重要的类型是句柄(handle),第九章中将讨论这一类型。
类型映射及类型转换
正如所知,你不能把一个变量赋给另一个不同类型的变量,如果你需要这么做,有两种方法供选择。第一种方法是采用类型映射(Typecasting),它使用一个带有目标数据类型名的函数符号:
var N: Integer; C: Char; B: Boolean;begin N := Integer (‘X‘); C := Char (N); B := Boolean (0);
你可以在字节长度相同的数据类型之间进行类型映射。在有序类型之间或实型数据之间进行类型映射通常是安全的,指针类型及对象之间也可以进行类型映射 ,只要你明白自己在做什么。
然而,一般来说类型映射是一种较危险的编程技术,因为它允许你访问一个似是而非的值,该值好象是其它值的替身。由于数据类型的内部表示法之间通常互相不匹配,所以当遇到错误时会难以追踪,为此你应尽量避免使用类型映射。
第二种方法是使用类型转换例程。表3.4中总结了各种类型转换例程。其中有些例程所涉及的数据类型将在下一节中讨论。 注意表中没有包括特殊类型(如TDateTime 和variant)的转换例程,也没包括用于格式化处理的特殊例程,如Format 和FormatFloat 例程。
表3.4:类型转换系统例程
例程 | 作用 |
---|---|
Chr | 将一个有序数据转换为一个ANSI字符 |
Ord | 将一个有序类型值转换为它的序号 |
Round | 转换一个实型值为四舍五入后的整型值 |
Trunc | 转换一个实型值为小数截断后的整型值 |
Int | 返回浮点数的整数部分 |
IntToStr | 将数值转换为字符串 |
IntToHex | 将数值转换为十六进制数字符串 |
StrToInt | 将字符串转换为一个整型数,如字符串不是一个合法的整型将引发异常 |
StrToIntDef | 将字符串转换为一个整数,如字符串不合法返回一个缺省值 |
Val | 将字符串转换为一个数字(传统Turbo Pascal例程用于向后兼容) |
Str | 将数字转换为格式化字符串(传统Turbo Pascal例程用于向后兼容) |
StrPas | 将零终止字符串转换为Pascal类型字符串,在32位Delphi中这种类型转换是自动进行的 |
StrPCopy | 拷贝一个Pascal类型字符串到一个零终止字符串, 在32位Delphi中这种类型转换是自动进行的 |
StrPLCopy | 拷贝Pascal类型字符串的一部分到一个零终止字符串 |
FloatToDecimal | 将一个浮点数转换为包含指数、数字及符号的十进制浮点记录类型 |
FloatToStr | 将浮点值转换为缺省格式的字符串 |
FloatToStrF | 将浮点值转换为特定格式的字符串 |
FloatToText | 使用特定格式,将一个浮点值拷贝到一个字符串缓冲区 |
FloatToTextFmt | 同上面例程,使用特定格式,将一个浮点值拷贝到一个字符串缓冲区 |
StrToFloat | 将一个Pascal字符串转换为浮点数 |
TextToFloat | 将一个零终止字符串转换为浮点数 |
注意:在最近版本的Delphi Pascal 编译器中,Round 函数是以 CPU 的 FPU (浮点部件) 处理器为基础的。这种处理器采用了所谓的 "银行家舍入法",即对中间值 (如 5.5、6.5) 实施Round函数时,处理器根据小数点前数字的奇、偶性来确定舍入与否,如 5.5 Round 结果为 6,而 6.5 Round 结果也为6, 因为 6 是偶数。
结束语
本章讨论了Pascal的基本数据类型。Pascal语言还有一个非常重要的特征:它允许编程者自定义数据类型,称为“用户自定义数据类型”,这在下一章进行讨论。
下一章: 用户自定义数据类型
第五课 详解数据类型