1

MB をバイトに変換する小さな関数を書きましたが、int64 にバグがあるようです。ドキュメントによると、int64 の範囲は -9223372036854775808 から 9223372036854775807 ですが、私の結果は大きく異なります。

Const FreeSpace = 67100;

var FreeSpaceConverted :int64;
.
.
.

FreeSpaceConverted := FreeSpace shl 20;

FreeSpace に 67100 の値を使用すると、70359449600 ではなく 1639972864 の値になります。変換がスペースを使い果たし、ラップアラウンドしたことは明らかです。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 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 の別の質問への回答を参照してください。

于 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 に答える
-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;

Inc(A) を開始します。// 動作します Inc(B); // 動作しないだけでなく、コンパイル エラーが発生します end;

比較 型なし定数 型付き定数 C #define A 20 long a = 20;
パスカル定数 A = 20; const A: 整数 = 20;
アセンブリ A equ 20 Add 20 ; ダブルワード、整数 32 ; アセンブリで同等

于 2013-03-02T01:49:03.463 に答える