【问题标题】:E2099 Overflow in conversion or arithmetic operationE2099 转换或算术运算溢出
【发布时间】:2014-04-21 20:39:25
【问题描述】:

我想将 int64 与这样的变量进行比较:

const GB=1073741824;
if DiskFile.Size< 1*GB then 

它适用于 1 但不适用于 3:

if DiskFile.Size< 3*GB then 

这篇文章 (Strange Delphi integer multiplication behavior) 解释了原因。我同意这个解释。 2*GB 的结果不适合“整数”。我不明白的是为什么编译器选择整数而不是 int64?如以下情况:

if DiskFile.Size< 3073741824 then      <--------- almost 3GB

行得通。


有什么方法可以在不为 1GB、2GB、3GB、4GB 等定义新常量的情况下以 3*GB 样式(使用常量)编写最后一行代码?

【问题讨论】:

    标签: delphi


    【解决方案1】:

    这里首先要明确的是,整数溢出发生在编译器中。编译器必须评估您的表达式,因为它是 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 类型。编译器可以选择其中任何一个。似乎编译器在有符号和无符号类型之间进行选择时,会选择有符号类型。

    但是人们可能会想象以下程序的行为方式相同,但SmallintWord 代替了IntegerCardinal

    {$APPTYPE CONSOLE}
    
    const
      C1 = 10922; // high(Smallint) div 3
      C2 = C1+1;
    
    begin
      Writeln(3*C1);
      Writeln(3*C2);
      Readln;
    end.
    

    但是不,这个程序可以编译。所以,在这一点上,我放弃了documentation,它似乎与编译器的实际行为关系不大。

    我最好的猜测是整数真​​常数的处理方式如下:

    1. 如果在Integer范围内,则为Integer类型。
    2. 否则,如果在Cardinal范围内,则为Cardinal类型。
    3. 否则,如果在Int64范围内,则为Int64类型。
    4. 否则,如果在UInt64范围内,则为UInt64类型。
    5. 否则是编译器错误。

    当然,所有这些都假定编译器计算常量表达式的规则遵循与语言其余部分相同的规则。我不确定情况是否如此。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-05-15
      • 2011-05-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多