这里首先要明确的是,整数溢出发生在编译器中。编译器必须评估您的表达式,因为它是 constant expression,并且它们由编译器评估。
关于编译器如何处理您的表达式的文档有点稀疏(我在这里很客气)。我们可以推断,至少凭经验,编译器尝试在有符号整数上下文中执行3*GB。从错误消息中可以清楚地看出这一点。
您需要强制编译器在 Int64 上下文中计算表达式。演员表将强制:
if DiskFile.Size< Int64(3)*GB then
....
另一种选择是使常量具有Int64 类型:
const
GB = Int64(1073741824);
虽然我想我会这样写:
const
KB = Int64(1024);
MB = 1024*KB;
GB = 1024*MB;
只要GB 是 64 位类型,那么您就可以恢复为:
if DiskFile.Size < 3*GB then
....
我想详细说明我上面的第二段。我们如何判断编译器在 32 位有符号整数上下文中执行算术运算?以下程序表明是这样的:
{$APPTYPE CONSOLE}
const
C1 = 715827882; // MaxInt div 3
C2 = C1+1;
begin
Writeln(3*C1);
Writeln(3*C2);
Readln;
end.
第一个表达式 3*C1 编译,第二个表达式失败并出现 E2099。第一个表达式不会溢出有符号的 32 位整数,第二个会溢出。
查看documentation 时,不清楚真正的常量1073741824 应该是Integer 还是Cardinal 类型。编译器可以选择其中任何一个。似乎编译器在有符号和无符号类型之间进行选择时,会选择有符号类型。
但是人们可能会想象以下程序的行为方式相同,但Smallint 和Word 代替了Integer 和Cardinal:
{$APPTYPE CONSOLE}
const
C1 = 10922; // high(Smallint) div 3
C2 = C1+1;
begin
Writeln(3*C1);
Writeln(3*C2);
Readln;
end.
但是不,这个程序可以编译。所以,在这一点上,我放弃了documentation,它似乎与编译器的实际行为关系不大。
我最好的猜测是整数真常数的处理方式如下:
- 如果在
Integer范围内,则为Integer类型。
- 否则,如果在
Cardinal范围内,则为Cardinal类型。
- 否则,如果在
Int64范围内,则为Int64类型。
- 否则,如果在
UInt64范围内,则为UInt64类型。
- 否则是编译器错误。
当然,所有这些都假定编译器计算常量表达式的规则遵循与语言其余部分相同的规则。我不确定情况是否如此。