pascal精要教程,要求加精(二)_派派后花园

用户中心 游戏论坛 社区服务
发帖 回复
阅读:517 回复:0

pascal精要教程,要求加精(二)

刷新数据 楼层直达
1023121

ZxID:1238825

等级: 牙牙学语
举报 只看楼主 使用道具 楼主   发表于: 2008-04-12 0
第三章 类型、变量及常量

最初的Pascal 语言是以一些简单的概念为基础建立起来的,这些概念现在普遍出现在编程语言中。最重要的概念当属数据类型,数据类型决定了变量可取的值,以及可在这些值上进行的操作。Pascal 数据类型的概念强于C语言及早期的BASIC语言,在C语言中算术数据类型是可以互换的,而早期的BASIC语言中根本没有与数据类型相似的概念。

变量
Pascal 变量在使用前必须声明,声明变量时必须指定一种数据类型。下面是变量声明的例子:

var
  Value: Integer;
  IsCorrect: Boolean;
  A, B: Char;

关键字var可以在许多地方使用,例如放在函数或过程的开始部分,用来声明函数或过程的局部变量;也可以放在单元中,用于声明全程变量。var关键字之后是一组变量名列表,每个变量名后跟一个冒号和数据类型名,一行中可以声明多个变量,如上例中最后一句。

一旦变量的类型被指定,你只能对变量执行该变量类型支持的操作。例如,在判断操作中用布尔值,在数字表达式中用整型值,你不能将布尔值和整型值混用(在C语言中可以这样)。

使用简单的赋值语句,可写出下面的代码:

Value := 10;
IsCorrect := True;

但下面的语句是不正确的,因为两个变量数据类型不同:

Value := IsCorrect; // error

在Delphi中编译这句代码,会出现错误信息:Incompatible types: 'Integer' and 'Boolean'.(类型不兼容:‘整型’和‘布尔型’)。象这样的错误通常是编程错误,因为把一个 True 或 False 的值赋给一个整型变量没有什么意义。你不该责怪Delphi 提示这样的错误信息,代码中有不对的地方Delphi当然要提出警告。

把变量的值从一种类型转换到另一种类型往往不难做到,有些情况下类型转换会自动实现,不过一般情况下需要调用特殊的系统函数,通过改变数据内部表示来实现类型转换。

在Delphi 中,当你声明全程变量时,你可以赋给它一个初值。例如,你可以这样写:

var
  Value: Integer = 10;
  Correct: Boolean = True;

这种初始化方法只能用于全程变量,不能用于过程或方法的变量。

常量
对于在程序运行期间保持不变的值,Pascal 允许通过常量来声明。声明常量不必特定数据类型,但需要赋一个初值。编译器会根据所赋初值自动选用合适的数据类型。例如:

const
  Thousand = 1000;
  Pi = 3.14;
  AuthorName = 'Marco Cantù';

Delphi 根据常量的值来决定它的数据类型。上例中的Thousand 变量,Delphi会选用SmallInt数据类型 (短整型--能容纳Thousand变量的最小整数类型)。如果你想告诉Delphi 采用特定的类型,你可在声明中加入类型名,方法如下:

const
  Thousand: Integer = 1000;

对于声名的常量,编译器有两种编译选择:第一种为常量分配内存,并把常量的值放入内存;第二种在常量每次使用时复制常量值。第二种方法比较适合简单常量。

注意:16位的Delphi 允许你在程序运行期间改变已定义的常量值,就象一个变量一样。32位的Delphi为了向后兼容仍容许这种操作,只要你附加 $J 编译指令,或选择工程选项对话框中Compiler (编译器) 页的Assignable typed constants复选框就行。尽管如此,这里我还是要强烈建议万不得以不要使用上述操作,因为把新值赋给常量将使编译器不能对常量进行优化,与其如此不如直接声明一个变量。

资源串常量
当定义字符串常量时,你可这样写:

const
  AuthorName = 'Marco Cantù';

从Delphi 3 开始,你可以用另一种方式写:

resourcestring
  AuthorName = 'Marco Cantù';

上面两个语句都定义了一个常量,也就是定义了一个在程序运行期间保持不变的值,但两者的实现过程却不同,用resourcestring 指令定义的字符串变量将被保存到程序资源的字符串表中。从例子ResStr你可了解资源串的实际作用,例子中设置了一个按钮, 相应代码如下:

resourcestring
  AuthorName = 'Marco Cantù';
  BookName = 'Essential Pascal';

procedure TForm1.Button1Click(Sender: TObject);
begin
  ShowMessage (BookName + #13 + AuthorName);
end;

以上代码中的两个字符串将分两行输出显示,因为字符串被分行符 #13 隔开。

有趣的是,当你用资源编辑器打开执行文件时,你会在程序资源中看到你所定义的字符串。这意味着字符串并没有进入编译代码,而是保存在执行文件 (EXE文件) 的一个单独区域。

注意:简而言之,采用资源的好处一方面可让Windows 来完成有效的内存处理,另一方面不用更改源代码就可实现程序的本地化 (把字符串翻译成不同的语言)。

数据类型
Pascal 中有多种预定义的数据类型,它们可分为三大类:有序数据类型,实数类型和字符串类型。下面我们先讨论有序类型和实数类型,字符串类型放在以后讨论。同时这一节还将介绍几种Delphi 库中定义的类型 (不是编译器预定义的类型),这些类型也可看作是预定义的类型。

Delphi 还包括一种无类型的可变数据类型,称作variant,在本书的第十章将讨论这一类型。variant是一种无需类型检测的数据类型,它在Delphi 2 中引入,用于处理OLE Automation(OLE 自动化)。

有序类型
有序类型是建立在概念“顺序”或“序列”基础上的数据类型。你不仅可比较两个有序值的大小,而且可以求取给定有序值的前驱及后继,或者计算它们的最大或最小值。

三种最重要的预定义有序类型是整数类型、布尔类型和字符类型(Integer,Boolean,Char)。各种类型根据其内部表示和取值范围不同又可进一步细分。表3.1列出了表示数字的有序数据类型。

表 3.1: 表示数字的有序数据类型

大小 有符号值域 无符号值域
8 bits ShortInt
-128 to 127 Byte
0 to 255
16 bits SmallInt
-32768 to 32767 Word
0 to 65,535
32 bits LongInt
-2,147,483,648 to 2,147,483,647 LongWord (从 Delphi 4)
0 to 4,294,967,295
64 bits Int64

16/32 bits Integer Cardinal


从表中可看到,不同数据类型与不同的数据表示法相对应,这要取决于数据值的数位和符号位。有符号类型的数值可正可负,但取值范围较小,因为符号位占一个数位。下一节在例Range中说明了每种类型的实际取值范围。

表中最后一组类型标志着16/32,它表明其数值表示方法在16位和32位Delphi中不同,该组的Integer及Cardinal 类型比较常用,因为它们与CPU内部的数字表示法相对应。

Delphi 4中的整数类型
在 Delphi 3中,Cardinal类型所表示的32位无符号值实际占31位,取值最高为20亿。Delphi 4新增了一种无符号数字类型--LongWord,它是真正的32位值,取值最高达40亿。现在Cardinal 类型已成了LongWord类型的别名,只是LongWord能容纳大于20亿的无符号数,而且它的数值表示法与CPU内部数值表示法一致。

Delphi 4 中新增的另一个数据类型是Int64 类型,这一类型能表示长达18个数字的整数。系统中的有序类型例程(如High 和Low)、数字例程(如Inc 和 Dec)及字符串转换例程(如IntToStr)都支持这一新类型。反过来,有两个新增的专用函数StrToInt64 和 StrToInt64Def支持从字符串向数字的转换。

布尔类型
布尔值不同于布尔类型,平时很少用到。ByteBool、 WordBool 和LongBool这三种布尔类型的布尔值比较特殊,只在Windows API 函数中才用到它们。

在Delphi 3 中,为了与Visual Basic 和 OLE Automation兼容,修改了ByteBool、 WordBool 和LongBool的布尔值,将TRUE值设置为1,FALSE值仍为0;Boolean类型布尔值保持不变(TRUE为1,FALSE为0)。如果在Delphi 2代码中使用了布尔值显式类型转换 ,那么在以后的Delphi中可能会出错。

字符类型
字符有两种不同的表示法:: ANSIChar 和 WideChar。第一种类型代表 8 位的字符,与Windows一直沿用的ANSI(美国国家标准协会)字符集相应;第二种类型代表 16 位的字符,与Windows NT、Windows 95 和 98支持的双字节字符(Unicode)相应。在Delphi 3 中,Char 类型字符与ANSIChar一致。切记,不管在什么环境,前 256 个Unicode 字符与ANSI 字符是完全一致的。

常量字符可用代表它们的符号表示,如‘k’,也可用数字符号表示,如 #78。后者还可用Chr函数表示为 Chr(78),用Ord函数可作相反的转换Ord(k)。

一般来说,对字母、数字或符号,用代表它们的符号来表示较好;而涉及到特殊字符时用数字符号较好。下面列出了常用的特殊字符:

#9 跳格 (Tab 键)
#10 换行
#13 回车 (Enter 键)
一个例子:Range
为使你对一些有序类型的不同取值范围有一个认识,我写了一个名为Range 的Delphi程序简例。结果见图3.1。

图3.1 简例Range显示有序数据类型信息(本例中采用整型)



Range 程序基于一个简单的窗体,上面有六个按扭 (按有序数据类型命名),还有几个标签(Label)用于显示信息,见图3.1。窗体最左边的一列标签显示的是静态文本,左边第二列标签在每次单击按扭时显示数据类型信息。

每当你按一下窗体右边的一个按钮,程序就会更新第二列标签的显示内容,显示的内容包括数据类型、字节数、该类型可存储的最大值和最小值。每个按钮都带有各自的onClick 事件,因为各自的计算代码略有不同。例如,以下是Integer按钮(BtnInteger)onClick 事件的源代码:

procedure TFormRange.BtnIntegerClick(Sender: TObject);
begin
  LabelType.Caption := 'Integer';
  LabelSize.Caption := IntToStr (SizeOf (Integer));
  LabelMax.Caption := IntToStr (High (Integer));
  LabelMin.Caption := IntToStr (Low (Integer));
end;

如果你有Delphi 编程经验,你可以看一下程序的源代码,弄明白程序到底是如何工作的。对于初学者,注意一下SizeOf、 High、 Low这三个函数的使用就可以了。High、 Low两个函数返回与参数相同的有序类型(这里是整型),SizeOf 函数返回整型数据。函数的返回值先用IntToStr 函数转成字符串,然后赋给三个标签的caption属性 。

其他按钮事件与上面相似,唯一的不同点在于传递给函数的参数类型是不同的。图3.2 显示了Windows 95 下的16位Delphi编译程序的执行结果。比较图3.1和图3.2,可以看出16位整型和32位整型之间的差异。

图3.2 :16位Delphi中Range程序运行结果显示的整型信息



整型类型的字节大小取决于你所使用的CPU和操作系统。在16位的Windows中,整型变量占两个字节,在32位的Windows中,整型变量占4个字节。因此,在两个环境中编译的Range程序会得到不同的结果。

如果你的程序对整数类型的字节大小没有特殊要求,Integer 类型在不同版本中的差异并不是个大问题。如果你在一个版本中保存了一个整数,那么在另一个版本中取出这个整数时可能会遇到一些问题,这种情况下,你应该采用平台无关的数据类型如 LongInt 或 SmallInt。对于数学计算或非特殊的代码中,你最好的选择是坚持使用平台相应的标准整型,这就是说,使用CPU最喜欢的整型类型。当处理整数时,Integer 应是你的首选,不到迫不得已最好不要采用其他的整型类型。

有序类型系统例程
Pascal 语言和Delphi System 单元中定义了一系列有序类型操作例程,见表 3.2。C++ 程序员会注意到其中的Inc 例程,它可与 ++ 和 += 运算符对应(Dec 例程也同样)。

表 3.2: 有序类型系统例程

例程 作用
Dec 将例程中的参数值递减1或一个特定的值,其中特定值可在第二个可选参数中定义 
Inc 将例程中的参数值增加1或一个特定的值 
Odd 如果参数为奇数返回真 
Pred 根据参数在其数据类型定义中的序列,返回参数值的前驱值 
Succ 返回参数值的后继值 
Ord 返回参数值在其数据类型值集合中的序号 
Low 返回参数对应的有序数据类型的最小取值 
High 返回参数对应的有序数据类型的最大取值 


注意,当有些例程用于常量时,编译器会自动用计算值替代例程。例如你调用High(X) ,设定X为一个整数,那么编译器会用整数类型中最大的可能值代替这个表达式。

实数类型
实数类型代表不同格式的浮点数。Single类型占的字节数最小,为4个字节;其次是Double 浮点类型,占8个字节;Extended 浮点类型,占10个字节。这些不同精度的浮点数据类型都与IEEE( 电气和电子工程师协会)标准的浮点数表示法一致,并且 CPU数字协处理器直接支持这些类型,处理速度也最快。

Real 类型在Delphi 2 和 Delphi 3 中的定义与 16 位版本一样,都占 6 个字节。不过Borland公司一直不提倡使用这种类型,而建议用Single、 Double、 Extended 类型代替。这是由于 Real 这种 6 字节的旧格式既不受 Intel CPU 的支持,又没有列在官方的IEEE 实型中。为了完全解决这一问题,Delphi 4 不得不修改 Real 类型的定义,将其改成标准的 8 字节浮点型, 由此引起了兼容性问题,不过如果有必要,你可以采用下面编译指令克服兼容性问题,恢复Delphi 2 和 Delphi 3 的Real 类型定义:

{$REALCOMPATIBILITY ON}

另外还有两种奇怪的数据类型: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 带有一个Math 单元,其中定义了一些高级数学例程,这些例程包括三角函数(如ArcCosh 函数)、金融函数(如InterestPayment 函数)和统计函数(如MeanAndStdDev 过程)。有些例程,它的名字听起来很怪,如MomentSkewKurtosis 例程,它是作什么用的呢? 还是留你自己查吧。

日期和时间
Delphi 也用实型数表示日期和时间数据。但为了更准确起见,Delphi 特别定义了TDateTime 数据类型,这是一个浮点类型,因为这个类型必须足够宽,使变量能容纳年、月、日、时、分和秒、甚至毫秒。日期值按天计数,从1899-12-30开始,放在TDateTime 类型的整数部分;时间值则位于十进制数的小数部分。

发帖 回复