E2099 Overflow in conversion or arithmetic operation

后端 未结 1 1096
别那么骄傲
别那么骄傲 2021-01-22 02:51

I want to compare an int64 with a variable like this:

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

It works with 1 but not with 3:

1条回答
  •  清歌不尽
    2021-01-22 03:10

    The first thing to be clear of here is that the integer overflow occurs in the compiler. The compiler has to evaluate your expression because it is a constant expression and they are evaluated by the compiler.

    The documentation is a little sparse (and I am being kind here) on how the compiler treats your expression. We can infer, at least empirically, that the compiler attempts to perform 3*GB in a signed integer context. That is clear from the error message.

    You need to force the compiler to evaluate the expression in an Int64 context. A cast will force that:

    if DiskFile.Size< Int64(3)*GB then 
      ....
    

    Another option is to make the constant have type Int64:

    const 
      GB = Int64(1073741824);
    

    Although I think I'd write it like this:

    const
      KB = Int64(1024);
      MB = 1024*KB;
      GB = 1024*MB;
    

    So long as GB is a 64 bit type then you can revert to:

    if DiskFile.Size < 3*GB then 
      ....
    

    I'd like to elaborate on my second paragraph above. How can we tell that the compiler performs the arithmetic in 32 bit signed integer context? The following program suggests that this is so:

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

    The first expression, 3*C1 compiles, the second fails with E2099. The first expression does not overflow a signed 32 bit integer, the second does.

    When looking at the documentation, it is unclear whether the true constant 1073741824 should be of type Integer or Cardinal. The compiler could choose either. It seems that the compiler, when presented with a choice between signed and unsigned types, chooses signed types.

    But then one might imagine that the following program would behave in the same way, but with Smallint and Word taking the place of Integer and Cardinal:

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

    But no, this program compiles. So, at this point I am giving up on the documentation which appears to bear little relationship to the actual behaviour of the compiler.

    My best guess is that a integral true constant is handled as follows:

    1. If it is within the range of Integer, it is of type Integer.
    2. Otherwise, if it is within the range of Cardinal, it is of type Cardinal.
    3. Otherwise, if it is within the range of Int64, it is of type Int64.
    4. Otherwise, if it is within the range of UInt64, it is of type UInt64.
    5. Otherwise it is a compiler error.

    Of course, all of this assumes that the compilers rules for evaluating constant expressions follow the same rules as the rest of the language. I'm not certain that is the case.

    0 讨论(0)
提交回复
热议问题