序数类型包括整数、字符、布尔、枚举、子界等类型。序数类型定义了一个有序的值的集合,集合中的每个值(除第一个)都有一个唯一的前驱值,每个值(除最后一个)都有一个唯一的后继值。此外,每个值都有一个序号,类型中的序号决定值在类型中的顺序。大多数情况下,如果一个值的序号为n,那么它的前驱值的序号为 n - 1,后继值的序号为 n + 1。

  • 对于整数类型,值的序号就是其自身整数值。
  • 子界类型保留了其基类型的序号。
  • 对于其他序数类型,默认情况下,第一个值的序号为0,下一个为1,等等。枚举类型可以明确地忽略这一默认情况。
  • 一些预定义函数作用于序数类型和序数类型标识符,下面是最重要的几个:

函数

参数 返回值 备注
Ord 序数表达式 表达式的值的序号 不要使用Int64类型参数(见编者注中的Ord函数中不要使用Int64类型参数
Pred 序数表达式 表达式的值的前驱值 不要用于具有write过程的的属性
Succ 序数表达式 表达式的值的后继值 不要用于具有write过程的的属性
High 序数类型标识符或序数类型变量 类型中的最大值 也可以作用于短串和数组
Low 序数类型标识符或序数类型变量 类型中的最小值 也可以作用于短串和数组

例如,High(Byte)返回255,因为Byte类型的最大值是255;Succ(2)返回3,因为3是2的后继。
标准过程IncDec分别对序数变量递增和递减。例如对于序数变量I,Inc(I)等价于I := Succ(I),如果I是一个整数变量,还等价于I := I + 1。

编者注

序数临界值的操作
对序数类型进行PredSuccIncDec等操作,需要注意适用范围。下面两个例子说明了一些特点:
范例一:

var
B: Byte;
begin
B := 255;
B := Succ(B); { 执行后 B = 0 }
B := 0;
B := Pred(B); { 执行后 B = 255 }
B := 255;
Inc(B); { 执行后 B = 0 }
B := 0;
Dec(B); { 执行后 B = 255 }

end;

范例二:

type
TWeek = (wMon, wTue, wWed, wThu, wFri, wSat, wSun);
{ 序号对应于 0..6 }


var
D: TWeek;
begin
D := wSun;
D := Succ(D); { 执行后 D 越界,序号为 7 }
D := Pred(D); { 执行后 D = wSun }
D := wMon;
D := Pred(D); { 执行后 D 越界,序号为 255 }
D := wSun;
Inc(D); { 执行后 D 越界,序号为 7 }
D := wMon;
Dec(D); { 执行后 D 越界,序号为255 }

end;

从上面的范例中可以看出,Succ函数和Inc过程实际上是简单地对序号增加,而Pred函数和Dec过程则相反。在范例一中,由于BByte类型,占用一个字节的内存,因此在对其进行递增和递减时,值0和255可以被视为是相邻的(即可以视为:0的前驱是255,255的后继是0)。在范例二中,TWeek类型的变量D,也占用一个字节的内存(因为枚举元素共7个,所以该类型最多占用一个字节;而如果枚举的元素数量在256和65535之间,那么将为该类型分配2个字节,序号默认也从0开始;等等),而在执行递增和递减操作时,并没有自动将0和6视为相邻,而是作为0..255序号序列的一部分。因此,对于序数类型中临界值的前驱和后继,需要小心处理。

Ord函数中不要使用Int64类型参数
请看下面的代码:

var
I: Int64;
X: Int64;
begin
I := Int64(4294967296) + 1234567;
ShowMessage(IntToStr(I));//显示的是:4296201863
X := Ord(I);//执行后X得到的并不是预期的序号
ShowMessage(IntToStr(X));//显示的是:1234567
end;

也许这一不足将在Object Pascal未来的版本中得到弥补,尽管事实上也没有太大的必要性。