我写了一个小函数来将 MB 转换为字节,但是 int64 中似乎有一个错误。根据文档,int64 的范围从 -9223372036854775808 到 9223372036854775807,但我的结果不同......很多:
Const FreeSpace = 67100;
var FreeSpaceConverted :int64;
.
.
.
FreeSpaceConverted := FreeSpace shl 20;
对 FreeSpace 使用 67100 的值会得到 1639972864 而不是 70359449600 的值。很明显,转换用完了空间并回绕。 int64 的实际大小似乎是 70359449600 - 1639972864 = 68719476736 = 2^36 而它应该是 2^63-1。 36 的指数看起来很奇怪。这可能是编译器本身的数字扭曲吗?
此外,使用以下替代方法会给出错误“转换或算术运算溢出”,即使它不应该:
FreeSpaceConverted := FreeSpace * 1024 * 1024;
另一方面,以下替代方法确实有效:
FreeSpaceConverted := FreeSpace * 1024;
FreeSpaceConverted := FreeSpaceConverted * 1024;
这是正常行为吗?如果是这样,这一切的原因是什么?
最佳答案
您在问题中包含的所有代码在 Delphi 7 中都可以正常工作。
program Int64Test;
{$APPTYPE CONSOLE}
var
FreeSpaceConverted, FreeSpace: Int64;
begin
FreeSpace := 67100;
FreeSpaceConverted := FreeSpace shl 20;
Writeln(FreeSpaceConverted);
FreeSpaceConverted := FreeSpace * 1024 * 1024;
Writeln(FreeSpaceConverted);
Readln;
end.
输出
70359449600
70359449600
您的实际代码与您在问题中所述的不同。事实上,
FreeSpace
在您的代码中被声明为 32 位类型,可能是 Integer
.例如,我不得不在这里猜测一下:program Int64Test;
{$APPTYPE CONSOLE}
var
FreeSpace: Integer;
FreeSpaceConverted: Int64;
begin
FreeSpace := 67100;
FreeSpaceConverted := FreeSpace shl 20;
Writeln(FreeSpaceConverted);
FreeSpaceConverted := FreeSpace * 1024 * 1024;
Writeln(FreeSpaceConverted);
Readln;
end.
输出
1639972864
1639972864
如果我们启用溢出检查,那么乘法代码会导致溢出异常,正如您报告的那样。
现在考虑
FreeSpace shl 20
当FreeSpace
是一个整数。编译器将此解释为 32 位整数运算,并将更高有效位移出 32 位寄存器的末尾。您分配给 64 位整数的事实无关紧要。重要的是表达式中的数据类型。您可以通过对 Int64
进行强制转换来使代码按照您想要的方式运行。在右手侧。program Int64Test;
{$APPTYPE CONSOLE}
var
FreeSpace: Integer;
FreeSpaceConverted: Int64;
begin
FreeSpace := 67100;
FreeSpaceConverted := Int64(FreeSpace) shl 20;
Writeln(FreeSpaceConverted);
FreeSpaceConverted := Int64(FreeSpace) * 1024 * 1024;
Writeln(FreeSpaceConverted);
Readln;
end.
输出
70359449600
70359449600
如需更全面的讨论,请参阅 Barry Kelly's answer to another question .
关于德尔福 7 : int64 size bug?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10542957/