表达式和运算符
建立表达式没有通用的方法,因为要取决于所用的运算符,Pascal包括有逻辑运算符、算术运算符、布尔运算符、关系运算符和集合运算符等等。表达式可用于确定赋给一个变量的值、计算函数或过程的参数、或者判断一个条件,表达式也可以包含函数调用。表达式是对一个标识符的值而不是标识符本身进行运算。
所有编程语言中的表达式都是常量、变量、数值、运算符和函数值的合法组合。表达式可以传递给过程或函数的值参,但不能传递给过程或函数中的引用参数。
运算符及其优先级
如果你以前写过程序,那么你已经知道表达式是什么了。这里我专门讲一下Pascal 运算符的特殊部分:运算符的优先级。表2.2中按优先级分组列出了Pascal语言的运算符。
与大多数编程语言相反,Pascal语言中and和or运算符的优先级比关系运算符高。因此,如果你的代码为a < b and c < d,编译器首先会编译and运算符,由此导致编译出错。为此你应该把每个 < 表达式用小括号括起来: (a < b) and (c < d)。
同一种运算符用于不同数据类型时它的作用不同。例如,运算符 可以计算两个数字的和、连接两个字符串、求两个集合的并集、甚至给PChar 指针加一个偏移量。然而,你不能象在C语言中那样将两个字符相加。
另一个特殊的运算符是 div。在Pascal 中,你能用 / 计算两个数字(实数或整数)的商,而且你总能得到一个实型结果。如果计算两个整数的商并想要一个整型结果,那么就需要用 div 运算符。
表 2.2: Pascal语言中的运算符及其优先级
单目运算符 (最高优先级) |
|
@ |
取变量或函数的地址(返回一个指针) |
not |
逻辑取反或按位取反 |
乘除及按位运算符 |
|
* |
相乘或集合交集 |
/ |
浮点相除 |
div |
整数相除 |
mod |
取模 (整数相除的余数) |
as |
程序运行阶段类型转换 (RTTI运算符) |
and |
逻辑或按位求和 |
shl |
按位左移 |
shr |
按位右移 |
加减运算符 |
|
|
相加、集合并集、字符串连接或指针增加一个偏移量 |
- |
相减、集合差集或指针减少一个偏移量 |
or |
逻辑或按位或运算 |
xor |
逻辑或按位异或运算 |
关系及比较运算符(最低优先级) |
|
= |
判断是否相等 |
<> |
判断是否不相等 |
< |
判断是否小于 |
> |
判断是否大于 |
<= |
判断是否小于或等于,或是否是一个集合的子集 |
>= |
判断是否大于或等于,或是否是一个集合的父集 |
in |
判断是否是集合成员 |
is |
判断对象是否类型兼容 (又一个RTTI运算符) |
集合运算符
集合运算符包括并( )、差(-)、交(*)、成员检测(in),及一些关系运算符。要把一个元素添加到集合中,你可以采用集合并运算。下面是一个选择字体的Delphi 例子:
Style := Style [fsBold];
Style := Style [fsBold, fsItalic] - [fsUnderline];
另一种方法是利用标准过程Include 和Exclude,它们效率更高(但不能用于控件的集合类型属性,因为只能操纵一个元素):
Include (Style, fsBold);
变量
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 还包括一种无类型的可变数据类型,称作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内部的数字表示法相对应。
布尔类型
布尔值不同于布尔类型,平时很少用到。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中可能会出错。