32

私の最近のプログラミングのほとんどは、C/C++/C#/VB6 を使用して 32 ビット Windows で行われています。最近、顧客から私のコードが 64 ビット Windows で動作するかどうか尋ねられます。

私が使用しているレガシー機能のうち、64 ビット Windows で壊れる可能性があるものは何ですか? 私が考え、心配する必要がある現実世界の問題は何ですか?

もちろん、コードを 64 ビット OS でテストしますが、探すべき一般的な問題を知りたいです。私は既存のバイナリに関心がありますが、(可能な場合) 再コンパイルするときに何を心配するかについてコメントを受け付けています。

編集: これは 64 ビット移植のバグの素晴らしいリストです。

4

8 に答える 8

22

私に関する限り、C / C ++コードを64ビットWindowsに移植する上で最も重要なことは、 4ギガバイトチューニングで説明されているように、割り当てを有効にして(レジストリ値)アプリケーションをテストすることですMEM_TOP_DOWNAllocationPreference

テスト目的で、割り当てを強制的に上位アドレスから下位アドレスの前に割り当てるにはMEM_TOP_DOWN、呼び出すときに指定するVirtualAllocか、次のレジストリ値を0x100000に設定します。

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Memory Management\AllocationPreference

これはいつ問題になりますか?

  • /LARGEADDRESSAWAREMSVCリンカーオプションを使用して構築された(またはIMAGE_FILE_LARGE_ADDRESS_AWARE、などの他の方法でPEヘッダーにフラグが設定されている)既存の32ビットEXEがある場合editbin.exe、64ビットで4GBの仮想アドレス空間全体を取得します。 Windows、およびAllocationPreferenceレジストリ値セットを使用してそれらをテストする必要があります。
  • 大規模なアドレス対応EXEによってロードされる可能性のある既存の32ビットDLLがある場合は、AllocationPreferenceレジストリ値セットを使用してそれらをテストする必要があります。
  • C / C ++コードを64ビットのEXEまたはDLLに再コンパイルする場合は、AllocationPreferenceレジストリ値を設定してテストする必要があります。

C / C ++アプリケーションがこれらの3つのカテゴリのいずれかに該当し、MEM_TOP_DOWN割り当てを使用してテストしない場合、テストでコード内のポインタの切り捨て/符号のバグが検出される可能性はほとんどありません。

2番目に重要なことは、MSVCを使用していて、64ビット用にC / C ++コードを再コンパイルする場合、 64ビットビルドにコンパイラオプションを使用する/Wp64ことです。

  • これにより、コンパイラは、ポインタを切り捨てたり、より小さな整数型をポインタに拡張したりする型キャスト(reinterpret_castまたはCスタイルのキャストが使用されている場合でも)、およびその他の64ビット移植の問題に対して警告を発します。
  • はい、ドキュメントには、コンパイルする代わりに/Wp6464ビットプラットフォームをターゲットとするコンパイラを使用する必要があると記載されていますが、それだけではコンパイル時のポインタの切り捨て/拡張の問題は検出されません。64ビットを対象とするコンパイラを使用し、64ビットビルドのコンパイラオプション有効にする/Wp64と、コンパイル時に多くのポインタの切り捨て/拡張の問題が発生し、長期的には時間を節約できます。
  • 残念ながら、MSVC 2008では、これにより、各変換ユニットに対して、/Wp64オプションが非推奨であることを示す「コマンドライン警告」も生成されます。このオプションが32ビットビルド(実際には多くのtypedefに注釈を付ける必要がある悪意のあるハック)で非推奨になっている理由はわかりますが、64ビットビルド(実際に役立つ場合)でも非推奨になっているのは残念です。
于 2009-02-13T07:50:59.400 に答える
2

32ビットプログラムは64ビットウィンドウで正常に動作します。もちろん、デバイスドライバのような開発を行っていない限り。

ソフトウェアを初めて64ビットソフトウェアとしてコンパイルする場合は、次の点に注意する必要があります。

  • ポインタは64ビット幅ですが、intは32ビットです。ポインタをintに格納しないでください。コードが壊れます。
  • 64ビットプロセスには64ビットDLLが必要です。サードパーティのDLLに依存している場合は、それらも64ビットで提供されていることを確認してください。32ビットプロセスと64ビットプロセスの間で通信する必要がある場合は、WindowsでのIPCのさまざまな方法のいくつかが必要になります。関数を直接呼び出すことは問題外です。
  • 64ビットWindowsのシステムディレクトリは、32ビットWindowsのシステムディレクトリとは異なります。ハードコードされたパスがある場合は、それらを再度確認する必要がある場合があります。
于 2009-02-13T01:52:28.747 に答える
2

32 ビット プログラムについて話している場合は、Windows 64 がそれらを 32 ビットとしてエミュレーションで実行するため、実質的に心配する必要はありません。将来の Windows バージョン (Windows 7 など) で発生する問題は、64 ビット OS の問題ではなく、互換性の問題である可能性があります。

ただし、マネージ コードが "任意の CPU" ターゲット プラットフォーム用にコンパイルされていて、アンマネージ コード (PInvoke など) を呼び出している場合、または他のアセンブリに依存している場合は、注意すべき点がいくつかあります。x86/x64 CLR に関するScott Hanselman の投稿はこれをカバーしており、Win32/64 での CLR の適切な説明です。

64 ビットのネイティブ プログラムを開発する場合は、64 ビット Windows 用のプログラミング ガイドが役立ちます。それは主にポインタとデータ型のサイズに帰着します:)

于 2009-02-13T01:16:44.370 に答える
1

なんらかの理由で DLL インジェクションを行うと、問題が発生します。

于 2009-02-14T18:16:41.290 に答える
0

32 ビット エミュレーションは本当に防弾ですか? レジストリのレイアウトが少し異なっていることがわかりました。私はただ、典型的なものがうまくいかないのだろうかと思っています...

また、C:\windows\SYSTEM32 ディレクトリには、64 ビット DLL のみを含めることができます。32 ビット DLL がある場合は、C:\windows\syswow64\ に配置する必要があります。

于 2009-02-13T06:10:26.520 に答える
0

C/C++ の観点から....

明らかなことの 1 つは、int のサイズが 4 バイトではなく 8 バイトになることです。コードのいずれかがそれに依存している場合、予期しない結果が生じる可能性があります。構造体と変数のアラインメントがずれることがあります。#pragma pack で解決できるかもしれませんが、私はアラインメントとパッキングが苦手です。

int を含む共用体を使用すると、動作が変わる可能性があります。

int に基づくビットフィールド構造を使用している場合、余分な 32 ビットによって混乱が生じる可能性があります。サインビットは、あなたが思っていた場所にはありません。

16 進定数をコーディングし、符号が負になることが予想される場合は、問題が発生する可能性があります。例 0x8000000 は対数としての負の数、または 32 ビット整数です。64 ビット プラットフォームの整数としての 0x80000000 は、正の数です。符号ビットを直接設定するには、0x80000000 00000000 を使用する必要があります (読みやすくするための埋め込みスペース)

また、 size__t が適切に成長することを期待しています。MAX_INT に基づいて割り当てを行っている場合は、はるかに大きくなります。

このようなサイズの異常を避けるために、私は通常、int ではなく long を使用します。

于 2009-02-13T01:24:04.680 に答える