web-dev-qa-db-ja.com

Cで32ビットアプリケーションを64ビットアプリケーションに変換する

私は現在、Cで32ビットアプリケーションを64ビットアプリケーションに変換する作業を行っています。このアプリケーションは現在、x86アーキテクチャ(Windows、osx、Unix、Linux)で動作しています。そのため、コーディングを開始する前に、アプリケーションを変換するときに何を考慮する必要があるかを知りたいと思いました。

20
  1. 誰が書いたか調べてください。彼らはばかですか?彼らはあなた数年前のものですか?彼らに質問してもらえますか?彼らは複数のプラットフォームとシステムの存在に精通していますか?知ることプログラムの作者の考え方は、問題に遭遇したときに問題を理解するのに役立ちます。
  2. 64ビットマシン/ビルド環境を起動して実行します。
  3. Longをintに置き換えます。 LONGlongではないことに完全に注意してください。
  4. _(int)&x_キャストと入力を_intptr_t_に置き換え、_(unsigned int)&x_を_uintptr_t_に置き換えます
  5. 構造体を_char*_にキャストしてポインター演算を行うことに依存するものはすべて監査します。
  6. 4 = sizeof(void*)を想定した場合、正規表現で\ <4 \>を検索します
  7. 我慢して。問題を見つけたら、同じ問題が存在するかどうか他の場所を調べて、解決策をマクロでラップします。
  8. _#ifdef RUN64_または同様のものを使用しないようにしてください。 128ビットプラットフォームが流行した場合は、後悔するでしょう。
  9. プログラムの他の場所での移植性の違いを隠すいくつかの集中型マクロの観点から、すべての変更をカプセル化します。
  10. カバレッジテスターを使用して、すべてをカバーしたことを確認します(適切な場合)

[〜#〜] edit [〜#〜]コメントで提案されているように_uintptr_t_メモを追加しました。

27
geocar

まだ言及されていない潜在的な問題の1つは、アプリがディスクからバイナリデータを読み書きする場合(たとえば、freadを使用して構造体の配列を読み取る場合)、非常に注意深くチェックする必要があり、おそらく2つになることです。リーダー:1つはレガシーファイル用、もう1つは64ビットファイル用です。または、uint32_tヘッダーファイルから<stdint.h>などのタイプを慎重に使用する場合は、構造体をビットごとに互換性があるように再定義できます。いずれにせよ、バイナリI/Oは注意が必要です。

8
Norman Ramsey

これは、実際にはアプリケーションとそのコーディング方法によって異なります。一部のコードは64ビットコンパイラで再コンパイルでき、正常に機能しますが、通常、これはコードが移植性を考慮して設計されている場合にのみ発生します。

コードにネイティブタイプとポインターのサイズに関する多くの仮定がある場合、ビットパッキングハックが多い場合、またはバイト指定プロトコルを使用して外部プロセスと通信するが、ネイティブタイプのサイズに関するいくつかの仮定を使用している場合クリーンなコンパイルを行うには、いくらか、または多くの作業が必要になる場合があります。

ほとんどすべてのキャストとコンパイラの警告は、チェックアウトが必要な危険信号です。コードが最初から「警告クリーン」ではなかった場合、それは多くの作業が必要になる可能性があることの兆候でもあります。

5
CB Bailey

値に正しいタイプを使用した場合-例: size_tptrdiff_tuintptr_t、必要に応じてstdint.hからの固定サイズのint型-値のサイズをハードコーディングしなかった場合、コードはそのままで機能するはずです。

4
Christoph

64ビットに切り替えるときに直面する主な問題は、ポインターのサイズが異なることです(32ビットではなく64ビット)。プラットフォームによっては、整数のサイズとlongのサイズも異なる場合があります。

なぜこれが問題なのですか?コードでsizeof(int)== sizeof(void *)と想定されていない限り、そうではありません。これは厄介なポインタのバグにつながる可能性があります。

3
gnud

さて、基本的に、変更の数はかなり少ないですが、アプリケーションが最初からある程度移植可能であるように注意深く書かれていない場合、それは依然として主要なタスクになります。

主な違いは、ポインタの幅が64ビットであるということです。しかし他のほとんどのデータ型は変更されていません。 intはまだ32ビットであり、longもおそらく32ビットです。したがって、コードがintとpointersの間でキャストする場合、それは壊れます。同様に、メンバーへの特定のオフセットに依存する構造体などは、他のメンバーが大きくなる可能性があるために破損する可能性があるため、オフセットを変更します。

もちろん、コードはそもそもこれらのトリックに依存するべきではないので、理想的な世界では、これはまったく問題にはならず、単に再コンパイルするだけですべてが機能します。しかし、あなたはおそらく理想的な世界に住んでいないでしょう...;)

3
jalf

開発者向けのすべての64ビット:

64ビット開発 に関する記事

リンクコレクション 64ビットリソース

ツール Viva64

2
Andrew

Cでの32ビットプログラミングと64ビットプログラミングの2つの大きな違いは、sizeof(void *)とsizeof(long)です。発生する主な問題は、ほとんどのUnixシステムが64ビットの長さを定義するI32LP64標準を使用し、Win64が32ビットの長さを定義するIL32LLP64標準を使用することです。クロスプラットフォームコンパイルをサポートする必要がある場合は、32ビットおよび64ビット整数のアーキテクチャベースのtypedefのセットを使用して、すべてのコードが一貫して動作するようにすることができます。これは、C99標準の一部としてstdint.hの一部として提供されます。 C99コンパイラを使用していない場合は、独自の同等のコンパイラをロールする必要がある場合があります

他の場所で述べたように、変換の主な懸念事項は、sizeof(int)== sizeof(long)== sizeof(void *)を想定するコード、ディスクに書き込まれたデータをサポートするコード、およびクロスプラットフォームIPCのコードです。

この背後にある歴史の良いレビューについては、これを見てください 記事 ACMキューから。

2
Jeffrey Cohen

すでにたくさんの良い答えがあります。

Gimpel Lint の使用を検討してください。問題のある構成のタイプを正確に指摘できます。あなたの経験が私のようなものであれば、32/64ビットポートとは関係のないシステムの多くのバグも表示されます。

2
Darron