20

どのような形式のメモリ アドレス空間が使用されていますか?

今日、大規模でフラットな仮想アドレス空間が一般的です。歴史的には、ベースアドレスとオフセットのペア、セグメント番号とオフセットのペア、ワードアドレスとバイトまたは他のサブオブジェクトのインデックスなど、より複雑なアドレス空間が使用されてきました。 .

時々、さまざまな回答やコメントが、C (または C++) ポインターは本質的に整数であると主張します。これは、C (または C++) の不適切なモデルです。ポインター操作に関する C (または C++) の規則の一部は、間違いなくさまざまなアドレス空間が原因であるためです。たとえば、配列を超えてポインター演算を定義しないと、基本およびオフセット モデルでのポインターのサポートが簡素化されます。ポインター変換の制限により、アドレスと追加データのモデルのサポートが簡素化されます。

その繰り返しの主張が、この質問の動機となっています。C ポインターが必ずしも単純な整数ではないこと、およびポインター操作に対する C の制限が、サポートされるさまざまなマシンを考慮して適切であることを説明するために、さまざまなアドレス空間に関する情報を探しています。

有用な情報には次のものが含まれる場合があります。

  • さまざまなアドレス空間を持つコンピューター アーキテクチャの例とそれらの空間の説明。
  • 現在製造中のマシンでまだ使用されているさまざまなアドレス空間の例。
  • ドキュメントまたは説明への参照、特に URL。
  • アドレス空間が C ポインター規則をどのように動機付けるかについての詳細。

これは幅広い質問なので、それを管理するための提案をお待ちしています。単一の一般的に包括的な回答で共同編集を行うことができれば幸いです。ただし、それは当然の評判を与えることに失敗する可能性があります。複数の有用な貢献に賛成票を投じることをお勧めします。

4

4 に答える 4

17

想像できるほぼすべてのものが使用されている可能性があります。最初の主要な区分は、バイト アドレス指定 (すべての最新のアーキテクチャ) とワード アドレス指定 (IBM 360/PDP-11 より前ですが、最新の Unisys メインフレームはまだワード アドレスであると思います) の間です。ワードアドレス指定ではchar*、多くの場合、 ;void*よりも大きくなります。int*それらが大きくなくても、「バイトセレクター」は0である必要がある上位ビットにあるか、バイト以外の場合は無視されます。(たとえば、PDP-10 では、とが同じサイズであっても、 ifpは であるchar*こと(int)p < (int)(p+1)が多く、false になります。)intchar*

バイト アドレス マシンの中で、主要なバリアントは、セグメント化されたアーキテクチャとセグメント化されていないアーキテクチャです。どちらも今日でも広く普及していますが、Intel 32 ビット (48 ビット アドレスのセグメント化されたアーキテクチャ) の場合、より広く使用されている OS (Windows および Linux) の一部は、ユーザー プロセスを人為的に単一のセグメントに制限し、フラットなアドレス指定をシミュレートします。

最近の経験はありませんが、組み込みプロセッサにはさらに多様性があると思います。特に、過去には、コードとデータが独立したアドレス空間にあるハーバード アーキテクチャを組み込みプロセッサが使用することがよくありました (そのため、関数ポインタとデータ ポインタは、十分に大きな整数型にキャストされ、同等に比較できます)。 )。

于 2012-12-30T15:34:07.643 に答える
6

歴史的な好奇心以外では、あなたは間違った質問をしていると思います。

システムがたまたまフラットなアドレス空間を使用していたとしても、実際、今から最後まですべてのシステムがフラットなアドレス空間を使用していたとしても、ポインタを整数として扱うことはできません。

C および C++ 標準では、あらゆる種類のポインター演算が「未定義」のままになっています。コンパイラは、未定義の動作を回避し、それに応じて最適化すると想定するため、現在、どのシステムでも影響を受ける可能性があります。

具体的な例として、3 か月前に Valgrind で非常に興味深いバグが発生しました。

https://sourceforge.net/p/valgrind/mailman/message/29730736/

([スレッド全体を表示] をクリックし、[未定義の動作] を検索します。)

基本的に、Valgrind は、自動変数が特定の範囲内にあるかどうかを判断するために、小なりポインタと大なりポインタを使用していました。異なる集約内のポインター間の比較は「未定義」であるため、Clang は単純にすべての比較を最適化して、定数 true (または false; 忘れました) を返します。

このバグ自体が、興味深い StackOverflow の質問を生み出しました。

したがって、元のポインター演算の定義は実際のマシンに対応していた可能性があり、それ自体は興味深いかもしれませんが、実際には今日のプログラミングとは無関係です。今日関連するのは、使用しているシステムに関係なく、ポインターが整数、ピリオドのように振る舞うと単純に想定できないということです。「未定義の動作」は「何かおかしなことが起こる」という意味ではありません。これは、コンパイラが、ユーザーがそれに関与していないと想定できることを意味します。そうすると、コンパイラの推論に矛盾が生じます。そして矛盾から、何でも続きます...それはあなたのコンパイラがどれほど賢いかだけに依存します。

そして、彼らは常に賢くなっています。

于 2012-12-31T22:53:44.513 に答える