1

我写了一个小函数来将 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;

这是正常行为吗?如果是这样,这一切的原因是什么?

4

4 回答 4

12

您在问题中包含的所有代码在 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 20whenFreeSpace是一个整数。编译器将此解释为 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 对另一个问题的回答

于 2012-05-10T22:25:31.197 回答
2

我碰巧在这个系统上没有 D7,但我确实有 Delphi 2007,其中,这段代码:

var
  FreeSpaceConverted, FreeSpace:int64;
begin
  try
     FreeSpace := 67100;
     FreeSpaceConverted := FreeSpace shl 20;
     writeln(FreeSpaceConverted);
     readln;
  except
    on E:Exception do
      Writeln(E.Classname, ': ', E.Message);
  end;
end.

产生“70359449600”。

于 2012-05-10T22:27:45.713 回答
0

我正在使用德尔福 XE7。我认为问题在于将 32 位整数转换为 64 位整数。如果我使用您的代码,我会得到与您相同的结果。但如果我首先将 FreeSpace 类型转换为 int64,即

常量自由空间:int64 = 67100;

我得到正确的结果。

于 2017-08-31T04:24:50.237 回答
-1

好的,所以这条线不起作用 -> FreeSpaceConverted := FreeSpace shl 20;

也许你应该看这部分 -> FreeSpace shl 20;

是的,FreeSpace shl 20,你可能想看看这个 -> const -> FreeSpace = 67100;

也许 D7 将 FreeSpace 视为 Integer 32 常量?如果是这样,您可能希望将代码更改为这样的 -> const -> FreeSpace: Int64 = 67100;

你不需要无类型的常量,除非你想做这样的事情 var A: array [0..FreeSpace] of Integer 除此之外你不需要无类型的常量。

更多信息 在 Pascal 中,无类型常量就像是文本编辑器的替代品。您可以在使用数字的地方使用无类型常量。它不需要任何内存引用,它只是一个文本编辑器替换。您不能在该示例中进行任何操作: const A: Integer = 10; B = 20;

开始公司(A);// 它工作 Inc(B); // 不仅不会工作,还会产生编译错误 end;

比较无类型常量有类型常量 C #define A 20 long a = 20;
帕斯卡常数 A = 20; 常量 A:整数 = 20;
装配 A equ 20 添加 20 ; 双字,整数 32 ;组装等效

于 2013-03-02T01:49:03.463 回答