这里首先要明确的是,整数溢出发生在编译器中。编译器必须评估你的表达式,因为它是一个常量表达式它们由编译器评估。
关于编译器如何处理表达式的文档有点稀疏(我在这里很友善)。我们至少可以凭经验推断,编译器尝试执行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 位整数,第二个表达式会溢出。
当看着文档,尚不清楚是否为真实常数1073741824
应该是类型Integer
or Cardinal
。编译器可以选择其中之一。看起来,当编译器在有符号类型和无符号类型之间进行选择时,它会选择有符号类型。
但是人们可能会想象下面的程序也会以同样的方式运行,但是Smallint
and Word
取代Integer
and Cardinal
:
{$APPTYPE CONSOLE}
const
C1 = 10922; // high(Smallint) div 3
C2 = C1+1;
begin
Writeln(3*C1);
Writeln(3*C2);
Readln;
end.
但不,这个程序可以编译。所以,在这一点上我放弃了文档这似乎与编译器的实际行为关系不大。
我最好的猜测是,整数真常量的处理方式如下:
- 如果在范围内
Integer
,它的类型是Integer
.
- 否则,如果在范围内
Cardinal
,它的类型是Cardinal
.
- 否则,如果在范围内
Int64
,它的类型是Int64
.
- 否则,如果在范围内
UInt64
,它的类型是UInt64
.
- 否则是编译器错误。
当然,所有这些都假设编译器计算常量表达式的规则遵循与语言的其余部分相同的规则。我不确定情况是否如此。