簡単な要約
(これも上に置きます):
(0)ポインターをアドレスとして考えることは、多くの場合、優れた学習ツールであり、通常のデータ型へのポインターの実際の実装です。
(1)しかし、多くの場合、おそらくほとんどの場合、コンパイラへの関数へのポインタはアドレスではなく、アドレス(通常は2倍、場合によってはそれ以上)よりも大きいか、実際には関数のアドレスや以下のものなどを含むメモリ内の構造体へのポインタです。一定のプール。
(2)データメンバーへのポインターとメソッドへのポインターは、しばしば見知らぬものになります。
(3)FARおよびNEARポインターの問題があるレガシーx86コード
(4)安全な「ファットポインタ」を使用したいくつかの例、特にIBM AS / 400。
もっと見つけられると思います。
詳細:
UMMPPHHH !!!!! これまでの回答の多くは、かなり典型的な「プログラマウィニー」の回答ですが、コンパイラウィニーやハードウェアウィニーではありません。私はハードウェアweenieのふりをして、しばしばコンパイラweeniesで作業するので、2セント投入します。
多くの、おそらくほとんどのCコンパイラでT
は、型のデータへのポインタは、実際にはのアドレスですT
。
いいね。
しかし、これらのコンパイラの多くでさえ、特定のポインタはアドレスではありません。これを見るとわかりsizeof(ThePointer)
ます。
たとえば、関数へのポインタは、通常のアドレスよりもかなり大きい場合があります。または、間接参照のレベルが含まれる場合があります。 この記事Intel Itaniumプロセッサを含む1つの説明を提供しますが、他の説明も見ました。通常、関数を呼び出すには、関数コードのアドレスだけでなく、関数の定数プールのアドレス(コンパイラが生成する必要があるのではなく、定数が単一のロード命令でロードされるメモリ領域)も知っている必要があります。いくつかのLoad Immediate、Shift、およびOR命令からの64ビット定数。したがって、単一の64ビットアドレスではなく、2つの64ビットアドレスが必要です。一部のABI(アプリケーションバイナリインターフェイス)はこれを128ビットとして移動しますが、他のレベルは間接参照のレベルを使用し、関数ポインターは実際には前述の2つの実際のアドレスを含む関数記述子のアドレスです。どちらが良いですか?あなたの視点に依存します:パフォーマンス、コードサイズ、いくつかの互換性の問題-多くの場合、コードはポインターをlongまたはlong longにキャストできると想定していますが、long longが正確に64ビットであると想定している場合もあります。そのようなコードは標準に準拠していない場合がありますが、それでも顧客はそれを機能させたい場合があります。
私たちの多くは、NEAR POINTERとFAR POINTERSを備えた、古いIntel x86セグメントアーキテクチャの苦しい思い出を持っています。ありがたいことに、これらは今ではほとんど絶滅しているので、簡単な要約のみ:16ビットのリアルモードでは、実際の線形アドレスは
LinearAddress = SegmentRegister[SegNum].base << 4 + Offset
プロテクトモードでは、
LinearAddress = SegmentRegister[SegNum].base + offset
結果のアドレスは、セグメントに設定された制限に対してチェックされます。一部のプログラムは実際には標準のC / C ++ FARおよびNEARポインター宣言を使用しませんでしたが、多くの人が言っただけです*T
---しかし、コンパイラーおよびリンカースイッチがあったため、たとえば、コードポインターはポインターの近くにある可能性があり、 CS(コードセグメント)レジスタ。データポインターはFARポインターの場合があり、16ビットセグメント番号と48ビット値の32ビットオフセットの両方を指定します。さて、これらの両方の量は確かに住所に関連していますが、同じサイズではないため、どちらが住所ですか?さらに、セグメントには、実際のアドレスに関連するものに加えて、読み取り専用、読み取り/書き込み、実行可能などの権限も含まれていました。
より興味深い例であるIMHOは、IBM AS / 400ファミリーです(またはおそらくそうでした)。このコンピューターは、C ++でOSを実装した最初のコンピューターの1つです。このmachimeのポインターは通常、実際のアドレスサイズの2倍でした(例:このプレゼンテーションなど)。128ビットのポインタですが、実際のアドレスは48-64ビットでした、そしてまた、いくつかの追加情報、いわゆる機能と呼ばれ、読み取り、書き込み、およびバッファオーバーフローを防ぐための制限などのアクセス許可を提供しました。はい:これはC / C ++と互換性があります-これがユビキタスである場合、中国のPLAとスラブのマフィアはそれほど多くの西側のコンピューターシステムに侵入しません。しかし、歴史的に、ほとんどのC / C ++プログラミングはパフォーマンスのセキュリティを無視してきました。最も興味深いことに、AS400ファミリは、オペレーティングシステムが安全なポインタを作成することを許可しました。これは、非特権コードに与えることができますが、非特権コードは偽造または改ざんできませんでした。繰り返しになりますが、セキュリティは標準に準拠していますが、標準に準拠していないずさんなC / C ++コードの多くは、このような安全なシステムでは機能しません。ここでも、公式の基準があります。
次に、セキュリティsoapboxから降りて、(さまざまなタイプの)ポインタが実際にアドレスされないことが多い他のいくつかの方法について説明します。データメンバーへのポインター、メンバー関数メソッドへのポインター、およびそれらの静的バージョンは、通常の住所。このポストは 言います:
これを解決するには多くの方法があります[単一の継承と複数の継承、および仮想継承に関連する問題]。Visual Studioコンパイラがそれを処理する方法を次に示します。多重継承されたクラスのメンバー関数へのポインターは実際には構造です。そして、「関数ポインターをキャストするとサイズが変わる可能性があります!」と言い続けます。
(おそらく)セキュリティについての私の理解から推測できると思いますが、私はポインタが生のアドレスよりも機能のように扱われるC / C ++ハードウェア/ソフトウェアプロジェクトに携わってきました。
私は続けることができますが、あなたがアイデアを得ることを望みます。
簡単な要約
(これも上に置きます):
(0)ポインターをアドレスとして考えることは、多くの場合、優れた学習ツールであり、通常のデータ型へのポインターの実際の実装です。
(1)しかし、多くの場合、おそらくほとんどの場合、コンパイラへの関数へのポインタはアドレスではなく、アドレスよりも大きく(通常は2倍、時にはそれ以上)、実際にはメモリ内の構造体へのポインタであり、関数のアドレスや以下のようなものを含みます一定のプール。
(2)データメンバーへのポインターとメソッドへのポインターは、しばしば見知らぬものになります。
(3)FARおよびNEARポインターの問題があるレガシーx86コード
(4)安全な「ファットポインタ」を使用したいくつかの例、特にIBM AS / 400。
もっと見つけられると思います。