E2099 Overflow in conversion or arithmetic operation

delphi

Solution

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:

- If it is within the range of `Integer`, it is of type `Integer`.

- Otherwise, if it is within the range of `Cardinal`, it is of type `Cardinal`.

- Otherwise, if it is within the range of `Int64`, it is of type `Int64`.

- Otherwise, if it is within the range of `UInt64`, it is of type `UInt64`.

- 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.

Problem

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: ``` if DiskFile.Size< 3*GB then ``` This post (Strange Delphi integer multiplication behavior) explains why. I agree with that explanation. The result of 2*GB cannot fit in 'integer'. What I don't understand is why the compiler chooses integer instead the int64? As in the case of: ``` if DiskFile.Size< 3073741824 then <--------- almost 3GB ``` that works. There is any way to write the last line of code in the 3*GB style (using constants) BUT without defining a new constant for 1GB, 2GB, 3GB, 4GB, etc ?

Original source

Related problems