web-dev-qa-db-ja.com

ポインタのサイズはどれくらいですか?正確には何に依存していますか?

オンラインで検索したところ、いくつかのディスカッションは見つかりましたが、包括的な説明は見つかりませんでした。したがって、ポインタのサイズに関するすべてをカバーする答えを誰かが作成できれば、それは非常に役立ちます。答えは少なくとも以下のトピックをカバーするべきです

  1. ポインタのサイズは何に依存しますか?
  2. アーキテクチャーのどの機能がポインターのサイズに影響しますか? (詳細に)
  3. コンパイラーはポインターのサイズにどのように影響しますか?
24

ポインターは、高水準言語によって提供される抽象概念です。理論的には、幅はどのような幅でもかまいません。それは完全にコンパイラの気まぐれです。

実際には、これは通常、基盤となるハードウェアのメモリアドレスの幅に関連しています。これは、通常、コンパイラが実装する最も効率的なものだからです。ただし、例外もあります。たとえば、C++のメンバーへのポインターは、2つのエンティティ(関数と型の概念)を表す必要があるため、ハードウェアアドレスに直接マッピングされません。

しかし、それを別にしても、複雑さはまだあります。例えば:

  • 最近のほとんどのハードウェアでは、プログラムは物理アドレス(同じ幅ではない場合があります)ではなくvirtualメモリアドレスで動作します。カーネル空間のコードを書いているのでなければ。
  • 一部のアーキテクチャ(x86など)では、基盤となるハードウェアがセグメント化アドレス空間を示します。これは非常に複雑ですが、OSと仮想メモリシステムによって抽象化されています。カーネル空間のコードや本当に古いx86向けのコードを書いている場合は、それに対処する必要があります。
  • 現在のx86-64では、(仮想)メモリアドレスは実際には48ビット幅のみです。
  • x86-64は、32ビットと64ビットの両方の実行可能ファイルをサポートしています。
  • 仮想マシン内で実行している可能性があります。仮想マシンは、必要に応じて(基盤となる物理マシンに対して)何でも実行できます。
16

この質問は、もともと「言語にとらわれない」ではなく、CおよびC++のタグが付けられていました。 言語にとらわれない質問として、広すぎるためクローズする必要がありますしかし、OPが元のバージョンに戻すことを期待しているので、クローズすることには投票しません。 C/C++の質問として、非常に回答可能である一方で、あまりにも広すぎるとして閉じられ、その後、スコープが非常に広がって回答不可能になると、そのタグ付けを言語にとらわれないように変更することにより、現在は回答可能として再開されました。

私はC++の元の質問に答えていますが、Cの知識がほんの少し散りばめられています。

現在の「言語にとらわれない」質問は、1つの言語にとらわれない回答が試みられたにも関わらず、答えられないと思います。

1.ポインターのサイズは何に依存しますか?

通常のデータポインターの最小必要サイズは、ポイントされた型のオブジェクトまたは異なる関数のオブジェクトの可能なメモリロケーションの最大数に依存します。 n可能な場所を区別するには、ceil(lg2(n))ビットが必要です。

したがって、最小ポインタサイズは、可能な最大メモリサイズに依存します。

したがって、最小ポインタサイズは、ポイントされた型の配置にも依存します。古くなった一部のマシン、さらには一部の現存するマシン(メインフレーム?)でも、ハードウェアレベルのアドレス可能なメモリの単位は Word でした。 2または4バイト。次に、ワードアライメントされたデータを小さなポインターでアドレス指定できますが、char*、およびvoid*も大きくする必要があります。

したがって、§3.9.2/ 4のC++ 11標準では、「cvvoid*型のオブジェクトは、cvchar*と同じ表現および配置要件を持っている必要があります。」

C++のメンバー関数ポインターは、ポインターよりもオフセットに似ており、適切なポインターよりも大きいことがよくあります。


2.アーキテクチャーのどの機能がポインターのサイズに影響しますか? (詳細に)

主にC++から見たアドレス可能なメモリ範囲。

ただし、MS-DOSプログラミングでは、近く遠くのポインタが区別されていたことも思い出してください。 nearポインターは暗黙の64Kメモリーセグメントへのオフセットでしたが、farポインターはサイズの2倍で、セグメントセレクターとオフセットを組み合わせたものです。

(まだ)現代の32ビットPCプログラミングでは、CおよびC++ポインターは、原則としてnearポインターに似ており、6バイトのfarポインターはサポートされていません。このようなポインタを使用するには、アセンブリ言語などの他の言語を使用する必要があります。


3.コンパイラーはポインターのサイズに影響しますか?どうやって?

サイズは規格で規定されていないため、使用されるコンパイラとコンパイルオプションは、原則としてポインタサイズに影響を与える可能性があります。例えば。原則として、デバッグに役立つ情報を追加できます。または、前述のように、言語拡張では近くおよび遠くのポインタが存在する可能性があります。

メンバーポインターは(内部で)直接アドレスではないので、それらをどのように表現するか、およびそれらの大きさはコンパイラー次第です。

これは、使用するオプションによっても異なります。


4.ポインタにはどのような種類がありますか、またポインタはどのように異なりますか? (例:関数ポインターと基本データ型を指すポインターの違いはありますか?近くのポインターと遠いポインターなど)

C++ 03では、関数ポインターをデータポインターに変換したり、その逆を行うことはできませんでした。この制限は、ハーバードアーキテクチャのマシンをサポートし、さまざまなサイズの関数ポインターとデータポインターをサポートしました(前者はfar、後者はnearなど)。 C++ 11では、このような変換は条件付きでサポートされており、5.2.10/8では 不具合レポート195 の結果です。

Posix標準では、変換(関数ポインタ)→(void*)とその逆のサポートが必要であることは注目に値します。 dlsym関数の場合。

上記は事実上、オブジェクトポインターと関数ポインターが異なることを意味します。例えば。後者はアドレス演算をサポートしていません。また、メンバーポインターは適切なポインターとは異なり、オフセットに似ています。

最新のC++は、ニアポインターとファーポインターをサポートしていません。


5.言語はポインタに影響を与えますか? C対C++

Cは、この質問ではポインターと見なされる程度まで、メンバーポインターをサポートしていません。

それ以外は、C++の主な目標はCライブラリを直接使用できるようにすることであり、C標準は互換性のあるポインタ表現を必要とするC++標準に「組み込まれ」(C++ 11§17.5.1.5/ 1)ています。

Cは、C++がサポートしていない制限付きポインター、修飾子restrictをサポートしています。ただし、これは、ポインターの可能な値についてコンパイラーが持っている知識にのみ影響します。つまり、Cコンパイラはより最適化されたコードを生成できる可能性があります。