2013-02-21 24 views
5

C++固有の質問です。だから私は32ビット/ 64ビットプログラムを作ることについての質問を読んで、それは何かこれのようなものだった(申し訳ありません私は質問を見つけることができない、いつか前に私はそれを見て、私はそれを再び見つける:():あなたが "ポインタの仮定"をしない限り、あなたはそれを再コンパイルする必要があります。私の質問は、ポインタの仮定は何ですか?私の理解には、32ビットポインタと64ビットポインタがありますコード間でコードを見せてください。コードを書いている間、他の良い習慣を覚えておいてください。 。私はこの記事があることを知っています: How do you write code that is both 32 bit and 64 bit compatible? しかし、私は自分自身のような新しいプログラマーのためのいい例はありません。 32ビットストレージユニットのようなものです。それをもう少し打ち砕くためにホッピングしています。変換可能なコード、32ビット/ 64ビットの書き方は?

答えて

3

整形されたプログラム(つまり、C++の構文規則とセマンティクス規則に従って記述されたプログラムで、未定義の動作はありません)の場合、C++標準ではプログラムに一連の観察可能な動作が保証されます。観察可能な振る舞いは、プログラム内での不特定の振る舞い(実装定義の振る舞いを含む)によって異なります。指定されていない動作を回避するか、またはそれを解決すると、プログラムは特定の特定の出力を持つことが保証されます。この方法でプログラムを作成すると、32ビットまたは64ビットマシン上のプログラムに違いは見られません。次のように

異なる可能な出力を有することになるプログラムの単純な(強制)の例である:

int main() 
{ 
    std::cout << sizeof(void*) << std::endl; 
    return 0; 
} 

このプログラム意志そう(32ビットおよび64ビットマシン上の異なる出力を有するがありません必ずしも)。 sizeof(void*)の結果は、実装定義です。しかし、実装定義の動作が含まれていますが、明確に定義されたように解決されたプログラムを持っていることは確かに可能である:

int main() 
{ 
    int size = sizeof(void*); 
    if (size != 4) { 
    size = 4; 
    } 
    std::cout << size << std::endl; 
    return 0; 
} 

このプログラムは常にそれが実装定義の動作を使用しますという事実にもかかわらず、4を出力します。 int size = 4;をちょうど行ったことがあるので、これは馬鹿げた例ですが、プラットフォームに依存しないコードを書いている場合があります。

したがって、移植可能なコードを書くルールは、です。不特定の動作を回避または解決することを目的としています。それを超えたC++標準指定の基本的な種類の大きさについて何も仮定しないでください

  1. :ここ

    は、不特定の行動を避けるためのヒントを示します。すなわち、charは少なくとも8ビットであり、shortintは少なくとも16ビットであり、以下同様である。

  2. ポインタ・マジック(ポインタ型間のキャストまたは整数型のポインタの格納)は試行しないでください。

  3. charオブジェクト(シリアル化または関連タスク用)の値表現を読み取るためにunsigned char*を使用しないでください。

  4. reinterpret_castを避けてください。

  5. オーバーフローまたはアンダーフローの操作を実行する場合は注意してください。ビットシフト操作を行うときは慎重に考えてください。

  6. ポインタ型の算術演算には注意が必要です。

  7. void*を使用しないでください。

標準で不特定または未定義の動作がさらに多く発生しています。それは彼らを見上げる価値があります。 some great articlesオンラインでは、32ビットと64ビットのプラットフォームの間に経験するより一般的な違いのいくつかをカバーしています。 32ビット/ 64ビットの移植のための

+0

awsome anwser :)私が探していたもの: –

+0

@FredrikBostonWestmanそれから、それを受け入れるべきです! – gsamaras

3

"ポインタの仮定"は、他のデータ型に適合するポインタに依存するコードを書くときです。 int copy_of_pointer = ptr; - intが32ビット型の場合、ポインタの一部のみが格納されるため、このコードは64ビットマシンで動作しなくなります。

ポインタがポインタ型に格納されている限り、それはまったく問題ではありません。

は典型的には、ポインタは、そう、32ビットアーキテクチャ上で、32ビットの「機械語」の大きさであり、64ビットアーキテクチャ上で、すべてのポインタは64ビットです。しかし、これが真実でないいくつかのアーキテクチャがあります。私はこのようなマシンで自分自身を作ったことはありません[それは "far"と "near"ポインタを持つx86以外のものですが、今は無視しています]。

ほとんどのコンパイラは、ポインタが収まらない整数にポインタを変換すると、あなたに警告します。警告を有効にすると、問題の大部分が明らかになります。警告を修正してください。すぐに動作します。

1

は、32ビットコードと64ビットコードに違いはありません、C/C++やその他のプログラミング言語の目標は、彼らの可搬性、代わりのアセンブリ言語です。

唯一の違いは、すべての作業が自動的にあなたのコンパイラ/リンカによって行われているので、ちょうどそれについて考えていない、あなたがあなたのコードをコンパイルしますDISTRIBとなります。

しかし、64ビットディストリビューションでプログラミングする場合、SDLなどの外部ライブラリを使用する必要がある場合、コードをコンパイルするには外部ライブラリも64ビットでコンパイルする必要があります。知って

ことの一つは、あなたのELFファイルは32ビット1に比べて64ビットDISTRIBに大きくなります、それだけで、論理だということです。

ポインタのポイントは何ですか?ポインタをインクリメント/変更すると、コンパイラはポインティングタイプのサイズからポインタをインクリメントします。

含まれるタイプのサイズは、プロセッサのレジスタサイズ/作業するディストリビューションによって定義されます。

しかし、これについて気にする必要はありませんが、編集はすべてあなたのために行います。

合計:そのため、32ビット版のディストリビューションでは64ビットELFファイルを実行できません。

+0

disrib you meen? –

+1

@FredrikBostonWestman:この回答は現代のLinux/BSDベースのオペレーティングシステムを前提としています。そのようなOSの「インプリメンテーション」はディストリビューションと呼ばれます。それらは、安定した完全なパッケージとして設計されています。このパッケージでは、実行されるアーキテクチャ用にすべてが具体的にコンパイルされます。クローズドソース技術でこのような利点を得ることは明らかです... – leftaroundabout

6

一般に、プログラムの動作は、(正確なサイズではない)任意のタイプのsizeof()に依存してはならず、明示的にも暗黙的にも(これには可能な構造体のアライメントも含まれます)

ポインタはそれらのサブセットに過ぎず、特別に作られていない限り、無関係なポインタタイプや整数間の変換に頼らざるを得ないことを意味します(例:intptr_t)。

同じように、ディスクに書き込まれたものの世話をする必要があります。組み込み型で、どこでも同じです。

外部データ形式などの理由で、必ずuint32_tのような明示的にサイズの指定されたタイプを使用する必要があります。

1

典型的な落とし穴がある:

プログラマはsizeof(ボイド*)== 4 *はsizeof(char)に暗黙の前提。 この前提を設定している場合、たとえば(「私は80バイトを割り当てるために20個のポインタが必要です」というように配列を割り当てると、バッファオーバーランが発生するため、コードが64ビットでブレークします。

"kitten-killer"、int x =(int)&something; (逆の場合、void * ptr =(void *)some_int)。やはりsizeof(int)== sizeof(void *)の前提です。これは、オーバーフローを引き起こすのではなく、データのロスを引き起こします。ポインタの上位32ビットです。

これらの問題の両方が(2種類のバイナリ表現のレベルで識別/インターチェンジ/同値を想定)タイプエイリアシングと呼ばれるクラスのものであり、そのような仮定は一般的です。 UN * Xのように、time_t、size_t、off_tがintであるか、Windows、HANDLE、void *およびlong互換であると仮定します。よく)。 C/C++コードでは、ローカル変数がスタックに割り当てられ、そこで使用されるスペースは、以下の点で32ビットと64ビットのモードで異なります。引数を渡すルールが異なるため(通常32ビットx86がスタック上にあります)、64ビットx86はレジスタの一部になります)。 32ビットでスタックサイズをデフォルト値に設定すると、64ビットでスタックオーバーフローが発生する可能性があります。 これは、クラッシュの原因として検出するのは比較的簡単ですが、アプリケーションの構成可能性に応じて修正するのが難しい可能性があります。

異なるコードサイズ/キャッシュフットプリント、異なるメモリアクセス特性/パターン、または異なる呼び出し規約により、32ビットと64ビットのコードのタイミングの違いによって、「キャリブレーション」が中断する可能性があります。言って、(int i = 0; i < 1000000; ++ i)sleep(0);おそらく32bitと64bitのタイミングが違うでしょう...

最後に、ABI(Application Binary Interface)です。現在のところ、64ビット環境の2つの主要な "ブランチ"が存在し、IL32P64(int64とint32_tはint32_t、uintptr_t/void *はuint64_tのみ、 (整数はint32_t、longはint64_t、uintptr_t/void *はuint64_tです)、LP64(UN * Xはint32_t、intはint32、uint40rはuint64_t)を使用していますが、異なるアライメントルールの「細分化」もあります。長さ、浮動小数点数、または倍精度をそれぞれのサイズで整列しますが、他のサイズは4バイトの倍数で整列するとみなされます。 32ビットLinuxでは、すべてが4バイトで整列しますが、64ビットLinuxでは、4バイトで長さが倍になり、8バイトの倍数で倍になります。 これらの規則の結果、多くの場合、データ型宣言が完全に同一であっても、bith sizeof(struct {...})および構造体/クラスメンバのオフセットは32ビット環境と64ビット環境で異なります。 配列/ベクトル割り当てに影響する以外に、これらの問題は/出力のデータにも影響します。スルーファイル - 32ビットアプリケーションが例えば構造体{char a; int b; char c、long d; double e}を同じアプリケーションが64ビット用に再コンパイルしたファイルに読み込むと、結果は期待通りにはなりません。 ちょうど与えられた例は、言語プリミティブ(char、int、longなど)に関するものですが、もちろん、size_t、off_t、time_t、HANDLE、本質的にすべての重要でない構造体/共用体など、あらゆるプラットフォーム依存型//class ... - エラーのためのスペースが大きいので、

そして、下位レベルの違いがあります。ハンドに最適化されたアセンブリ(SSE/SSE2/...)。 32bitと64bitには、レジスタの数が異なり、引数渡し規則が異なります。このようなことは、そのような最適化がどのように実行されるかに強く影響します。 32ビットモードで最高の性能を発揮するSSE2コードは、最高性能の64ビットモードを実現するために書き直す/強化する必要があります。

32ビットと64ビットでは、特にメモリ割り当て/管理に関して非常に異なるコード設計の制約もあります。 「32ビットで取得できるメモリを最大限活用する」ように慎重にコーディングされたアプリケーションは、メモリの割り当て/解放、メモリーマップファイルの使用方法、内部キャッシュなどの複雑なロジックを持っています。 64ビットで有害になる可能性があります。「単純に」利用可能な大きなアドレス空間を利用することができます。このようなアプリケーションは、64ビットの場合は正常に再コンパイルされるかもしれませんが、32ビットの最大限のピープホール最適化をすべて持たない「古代の単純な非推奨バージョン」よりも悪化します。

最終的には、エンハンスメント/ゲインに関するものでもあります。これは、部分的にはプログラミングで、部分的には設計/要件に入るものです。実際に64ビットから利益を得ているのですか? 64ビットで高速化/高速化するために、コードロジックに変更を加えたり、変更したりする必要がありますか? 32ビットの下位互換性を損なうことなくこれらの変更を行うことができますか? 32ビットターゲットに悪影響を与えないでください。拡張機能はどこにありますか、どれだけ得ることができますか? 大規模な商業プロジェクトでは、これらの質問に対する回答は、出発点がいくつかの既存の「マネーメーカー」であるため、ロードマップ上の重要なマーカーになることがあります...

+1

をご覧に値するhttp://www.viva64.com/en/a/0004/ – Saqlain

関連する問題