web-dev-qa-db-ja.com

最終的な64ビットコンパイラ用に32ビットDelphiプログラムをどのように準備する必要がありますか?

重複の可能性:
Delphi 2010およびUnicodeに移行するときに64ビットも準備する方法

64ビットDelphiコンパイラがまもなく登場すると思うので、現在32ビットは、64ビットコンパイラを使用すると、変更なしでコンパイルおよび動作します。

そして、一般的なルールがある場合、64ビットとしてコンパイルされる古いプログラムに体系的にどのような変更を加える必要がありますか?

64ビットコンパイラが突然ここに来るときに備えておくとよいでしょう...

どんな提案でも大歓迎です。

60
Petra

まず、免責事項:私はエンバカデロで働いていますが。私は雇用主のために話すことができません。私がこれから書くことは、架空の64ビットDelphiがどのように機能するかについての私自身の意見に基づいていますが、競合する意見や、代替の設計決定を行う他の予測または予期しない非互換性やイベントがある場合とない場合があります。

それは言った:

  • NativeIntとNativeUIntの2つの整数型があり、そのサイズはプラットフォームに応じて32ビットから64ビットの間で変動します。彼らはかなりの数のリリースのために出回っています。他の整数タイプは、ターゲットのビット数に応じてサイズを変更しません。

  • ポインタ値を整数にキャストする、またはその逆に依存する場所では、整数型にNativeIntまたはNativeUIntを使用していることを確認してください。 TComponent.Tagは、Delphiの新しいバージョンではNativeIntである必要があります。

  • 私は提案します非ポインタベースの値にはNativeIntまたはNativeUIntを使用しないでください。コードを32ビットと64ビットの間で意味的に同じに保つようにしてください。 32ビットの範囲が必要な場合は、整数を使用してください。 64ビットが必要な場合は、Int64を使用してください。そうすれば、コードは両方のビットで同じように実行されます。参照やTHandleなど、ある種のPointer値との間でキャストする場合にのみ、NativeIntを使用する必要があります。

  • 可能であれば、PByteまたはNativeIntよりも、ポインタ演算にNativeUIntを使用します。これはほとんどの目的に十分であり、通常の整数型と(簡単に)間違えられないため、よりタイプセーフです。その逆も同様です。

  • ポインターのようなものは、ポインターと同様のルールに従う必要があります。オブジェクト参照(明らかに)だけでなく、HWND、THandleなども同様です。

  • ヘッダーデータなど、文字列や動的配列の内部の詳細に依存しないでください。

  • 64ビットのAPI変更に関する一般的なポリシーは、64ビットAPIが必ずしもマシンを利用しないことを意味する場合でも、可能な場合は32ビットと64ビットの間で同じAPIを維持することです。たとえば、TListは、Count、インデックスなどを整数として保持するために、おそらくMaxInt div SizeOf(Pointer)要素のみを処理します。整数型はフロートしない(つまり、ビット数に応じてサイズを変更する)ため、顧客コードに波及効果を与えたくありません。整数型変数をラウンドトリップするインデックス、またはforループインデックスは切り捨てられ、微妙なバグを引き起こす可能性があります。

  • APIが64ビット用に拡張されている場合、追加のデータにアクセスするための追加の関数/メソッド/プロパティを使用して実行される可能性が高く、このAPIは32ビットでもサポートされます。たとえば、Length()標準ルーチンは、文字列型または動的配列の引数に対して整数型の値を返す可能性があります。非常に大きな動的配列を処理したい場合は、LongLength()ルーチンもあります。このルーチンの32ビットでの実装はLength()と同じです。 Length()は、2 ^ 32を超える要素を持つ動的配列に適用された場合、64ビットで例外をスローします。

  • これに関連して、言語でのナロー操作、特に64ビット値を32ビットの場所にナローするためのエラーチェックが改善される可能性があります。これは、Length()がInt64を返した場合に、Lengthの戻り値を整数型の場所に割り当てるという使いやすさに影響します。一方、特にLength()のようなコンパイラマジック関数の場合、たとえば、次のようなマジックの利点がいくつかあります。コンテキストに基づいて戻り値の型を切り替えます。しかし、魔法以外のAPIでも同様に利点を活用することはできません。

  • 動的配列はおそらく64ビットのインデックス作成をサポートします。 Java配列は、64ビットプラットフォームでも32ビットインデックスに制限されていることに注意してください。

  • 文字列はおそらく32ビットのインデックスに制限されます。動的配列も同様に機能する可能性のある、データの管理されたBLOBだけでなく、実際には文字列である4GB以上の文字列が必要な現実的な理由を思い付くのに苦労しています。

  • おそらく組み込みのアセンブラですが、Delphiコードと自由に組み合わせることができないなどの制限があります。 x64で従う必要のある例外とスタックフレームレイアウトに関するルールもあります。

80
Barry Kelly

まず第一に、 FreePascal はすでに64ビットのサポートを提供しています。ただし、Delphiではありません。
次に、Delphi1がDelphi2にアップグレードされたときに存在したのとほぼ同じ問題が予想されます。最大の問題は主にアドレス空間に関連することであり、ここでの問題はポインタが4から拡張されることです。バイトから8バイト。 WIN16では、以前は2バイトでしたが、ポインタにセグメントとオフセットを使用して64KBの境界を超えるにはトリックが必要でした。 (いくつかのタスクにデフォルトのセグメントを使用する可能性があります。)
特定のデータ型が現在よりも大きくなる可能性もあります。整数型はおそらく8バイトになります。 (Windows 2では2バイトでした。)列挙も大きくなる可能性があります。ただし、他のほとんどのデータ型は現在のサイズを維持する可能性が高いため、ここでの変更はそれほど多くありません。
もう1つの問題は、メモリ要件です。ポインタの長さは8バイトになるため、ポインタを大量に使用するアプリケーションは、より多くのメモリを消費します。 10.000ポインターのリストは、40.000バイトから80.000バイトに増加します。 32ビットシステムよりも少し多くのメモリを使用することをお勧めします。
速度も少し変わります。プロセッサは8バイトを同時に処理するようになったため、データをはるかに高速に処理できます。ただし、ポインタと一部のデータ型が大きくなるため、これらをデバイスまたはメモリに送受信するのが少し遅くなります。一般に、アプリケーションは一般的にわずかに高速になりますが、一部の部分は実際には遅くなる可能性があります。
最後に、Windows APIを変更すると、64ビットAPI関数を使用する必要があります。 Delphiコンパイラはコードが32ビットAPI関数を呼び出せるようにするために何か賢いことをするかもしれませんが、プロセッサがネイティブ64ビットモードとエミュレートされた32ビットモードを切り替えるため、パフォーマンスが低下します。

8
Wim ten Brink

Delphi 2009がUnicodeアプリケーションのみを作成すると発表されたとき、多くの同様の質問がありました。結局、ほとんどの既存のコードは変更なしで問題なく実行されたことが判明しました。トリッキーな部分は、SizeOf(Char) = 1とそれを実行している可能性のあるサードパーティコンポーネントを想定したコードでした。

64ビットDelphiへの移行も同様の経験になると思います。ポインタを使ってトリックを実行し、SizeOf(Pointer) = 4またはSizeOf(Pointer) = SizeOf(Integer)を想定するコードを除いて、すべてが箱から出してすぐに機能します。ポインタサイズの整数が必要な場合は、ハードコーディング_4_ではなくSizeOf(Pointer)を呼び出し、NativeIntまたはNativeUIntを使用することで、このような問題を今日すでに修正できます。

コードをDelphi2007で動作させる場合は、SizeOf(Pointer)ではなくSizeOf(NativeInt)を使用する必要があります。Delphi2007には、SizeOf(NativeInt)がではなく8を返すという残念なバグがあります。 4必要に応じて。これはDelphi2009で修正されました。

4
Jan Goyvaerts

コードによっては、32ビットと64ビットの両方のコンパイルをサポートするFreePascalを使用してコンパイルを試みることができます。コンパイラは、コード内の誤った場所の可能性について警告します。

Embarcaderoが64ビットの実装に関する公式情報を公開しない限り、簡単に伝えることはできません。ポインター、整数、カーディナルとの間のキャストは、オブジェクトのプロパティと参照を含むネイティブプラットフォームサイズであると想定してチェックする必要があります(つまり、ポインターであるTObjectプロパティに整数を格納するか、タグを使用して数値ではなく参照を格納します) )。

また、最大(最小)サイズで値をインクリメント(またはデクリメント)するときに、コードが「ラップアラウンド」効果に依存しないようにする必要があります。

データサイズに依存し、SizeOf()を正しく使用していない構造体のコードを確認してください。全体として、データサイズが重要な場合は常にSizeOf()が使用されます。サイズが変更される可能性がある場合、特にデータを32ビットコードと64ビットコードの間で交換する必要がある場合は、ファイルにデータを書き込んだり読み取ったりするコードを確認してください。

アプリケーションがAPIを呼び出し、Windowsメッセージを直接管理する場合は、Win64の変更を確認してください。ハンドコーディングされたASMコードは、64ビットの互換性をチェックする必要があります(64ビットアセンブラーを作成するためのはるかに厳しい規則があります)。

3
user160694

単純なアプリケーションの大部分は問題なく動作するはずです。私が見る限り、手動でポインタを使用するアプリケーションのみがリスクにさらされています。実際、ポインターが64ビットになり、整数またはカーディナル(デフォルトでは32ビットのまま)と一緒に計算に使用すると、問題が発生します。また、ポインタを引数として受け取るAPI関数の宣言では、(符号なし)ネイティブ整数型の代わりにcardinalsを使用するのが一般的だと思います。

どのプラットフォームでもうまく機能するコードを作成するには、ポインターと整数を同時に操作するときに、NativeUIntsの代わりにcardinals(IIRC、現在Deplhiコンパイラーはありません)を使用する必要があります。

3

明らかなポインタ<-> intタスクに加えて:(intptr/nativeint/ptrintなどを使用)

  • バイナリブロブとして持っているもの(DLLはOCXなど)はすべてアップグレードする必要があります。これには、ドングルなどの古いSDKが含まれる場合があります。
  • バイナリレベルで何かを行うすべてのツール(デバッガー、プロファイラー、電話ホームツール)は更新が必要な場合があります。
  • ほぼすべてのアセンブラおよびその他の非常に低レベルのトリック(たとえば、VMTレイアウト、デバッグ形式(トレースバック)、Jedi Apilibなどの動的ロードスタブに依存)を更新する必要があります
  • 自分で作成したすべてのヘッダーをチェックして、ポインタ<>整数で重要なパッキングの変更と誤訳を確認します。パッキングビットを過小評価してはなりません
  • Officeやその他の外部アプリとのインターフェースが変更される可能性があります
  • TComponent.tagは現在longintであるため、longintのままになる可能性があります。つまり、component.tagにポインターを詰め込むスキームが失敗する可能性があります。
  • x87 FPUはx64で非推奨になり、一般にSSE2がフローリングポイントに使用されます。そのため、浮動小数点とその例外処理はわずかに異なる動作をする可能性があり、拡張は80ビットではない可能性があります(ただし、64ビットまたはおそらく128ビット)。これは、異なるfpuワードを期待するCコードとインターフェイスするときの通常の丸め(コプロ制御)の変更にも関連しています。

レコードのパッキングの問題は、既存のヘッダーをwin64に移植するときに気付いたものです。

2

私の2セント:

  • 昔は、すべてのasmライターはUSEBASMにプッシュされていました

  • 外部asm64は受け入れ可能であり、古いものを使用するとxy.objコードが含まれますが、いずれにしても完全な書き直しが必要です。

  • デバッガーとCPU64:問題はこれがまだあるのか?

  • D64 Float Extended:これはまだ80ビットfloatとして維持されていますか?

HP

1
HpW

完全な推測として、特定のWordサイズに依存しないコード、またはコンパイラーの指示に基づいてWordサイズを適応させることができるコードは問題ありません。