16


0

C / C ++の変数はどのように機能しますか?

C / C ++の変数はどのように機能しますか?

つまり、ポインターは変数からのアドレスを格納し、それを参照するオブジェクトにアクセスするには逆参照する必要があるため、変数は使用時に自動的に逆参照されるポインターだと思います…​ それは理にかなっていますか?

10 Answer


29


変数は、コンピューター上のメモリ位置の抽象化(便利な名前)です。 C / C ++では、変数が* int *型の場合、整数値を保持するメモリアドレスの便利な名前になります。

また、変数は自動的に逆参照されるポインターではありません*。 変数は、保持するはずの値を保持するだけです。 ポインタの場合、メモリアドレスを保持し、整数の場合は整数値を保持し、浮動小数点数の場合は浮動小数点数を保持します…​ などなど


12


次の定義を考慮してください

char *string="abc";
int b = 10;
int *bptr = &b;

これを少し簡略化し、10進値を使用します。変数(名前)はアドレスのプレースホルダーであり、これらのアドレスには具体的な値が格納されます。

Adr  content
1000 a b c 0    // "abc" : string literal '\0' terminated
1004    1000    // *string: pointer to string (address 1000)
1008      10    // b = 10 : integer value
1012    1008    // *bptr  : pointer to &b

例えばを使用して printf( "%s \ n"、string);文字列全体をコピーするのではなく、文字列が始まるアドレスを指定します(参照渡し)。


8


変数の読み取り/書き込みとは、既知の場所でバイトを読み取り/書き込みすることです。 「位置を知る」は、コンパイラーによって知られている位置であり、次のいずれかです。

  • 固定アドレス。 コンパイラーは、グローバル変数のすべてのアドレスを知っています。 もし私達 グローバル変数の読み取り/書き込み、コンパイラは次のような命令を入力します: "アドレス0x00235A87のメモリの読み取り/書き込み"

  • スタックオフセットが修正されました。 ローカル変数はスタックにプッシュされます。 ポインタ スタックの最上部(「スタックポインタ」または「SP」)はプロセッサレジスタに格納されます。 コンパイラーは、スタックの先頭からのローカル変数のオフセットを知っています。 ローカル変数の読み取り/書き込みを行う場合、コンパイラは「アドレス 'SP-0x05’のメモリの読み取り/書き込み」のような命令を入力します。

  • プロセッサレジスタ。 変数が使用されると、プロセッサにロードされます レジスタ。 コンパイラはどのレジスタを知っています。 それらを使用するには、メモリの読み取り/書き込みは必要ありません。コンパイラは、「レジスタBの内容をレジスタAに追加する」などのレジスタを使用する命令を単に配置します。

変数へのアクセスは、実際にはプロセッサ命令の形式で記述されたアルゴリズムです。 変数は、固定メモリアドレス、計算されたメモリアドレス(レジスタに保持されている固定オフセットと値を使用)、またはプロセッサレジスタごとのアドレスです。 コンパイラは、メモリ/レジスタ間およびレジスタ/レジスタ間で変数の値を移動する命令を配置します。 変数はメモリ内に存在しない場合もあり、常にレジスタに保持されます。

あなたが言うことには、ある種の類推があります。

上記を考慮すると、ポインターはアドレス(整数)を保持する変数であることに注意してください。 ポインターを逆参照し、ポイントされた値を読み取る場合、2つの手順を実行する必要があります。 まず、他の変数と同様にポインター変数を読み取る必要があります。 その後、アドレスはレジスタにあります。 次に、「レジスタAに格納されているアドレスのメモリを読み取る」などの命令で、ポイントされた変数を読み取ります。


6


変数は単なる抽象化です。 参照、読み取り、および(場合によってはそのタイプによって)変更できる名前付き値の_idea_です。

ハードウェアのどこに保存されるかは、実装の詳細にすぎません。 _多くの場合、特定のメモリアドレスにデータを格納し、変数にアクセスするたびにそのアドレスを使用することで実装されます。その意味では、多くの場合、「自動参照解除ポインタ」です。

ただし、変数はメモリではなくレジスタに格納される場合があります。 その場合、アドレスがなく、ポインタを作成できません。

場合によっては、コンパイルされたコードにも存在しないことがあります。 コンパイラがコードを変換して変数が不要になる場合や、変数が単一のコンパイル時定数に変換される場合があります。

最終的に、変数はソースコードにのみ存在します。 コードが実行されると、変数は存在しなくなります。 一部の変数はメモリ位置に変換され、一部は完全に削除されるか、変数として認識できないものに変換されます。

たとえば、次のコードは

int x = 10;
y += 10;

xとyをメモリ位置として表すことでコンパイルでき、その後、「メモリアドレスxの値をメモリアドレスyの値に加算する」などの命令で加算が実行されます。

ただし、コンパイラーは定数10を命令自体にエンコードして、「メモリーアドレスyの値に10を加算」命令を生成することもできます。 確かに、 `x`は元のソースコードでは変数でしたが、もはやメモリの場所ではありません。 命令ストリームに直接エンコードされます。


4


あなたはすでに答えを受け入れていることを知っています、そしてこれはあなたの質問に直接答えません…​ あなたがそれを読みたいなら、これはあなたの啓発のためです。


2


ローカル変数は、メモリ内またはレジスタ内に存在するか、プログラム実行の異なる段階で2つの間を浮動するか、別の変数とスペースを共有できます。 コンパイラーは、変数に最も効率的なスペースを自由に割り当てます。

変数へのポインターを取得する場合、コンパイラーはその変数をメモリに配置する必要があります。そのため、変数は一意のアドレスを持ちます。 しかし、それへのポインタを取らない場合、変数は独自のCPUレジスタに残る可能性があります。 または、2つのローカル変数があり、両方を同時に使用しない場合、コンパイラはそれらを同じメモリまたはCPUレジスタに占有させることができます。


1


変数は、場所を参照する名前です。 場所は_compile time_に解決されます-コンパイラはコンパイル時に場所を計算し、すべての変数をそれぞれの場所に置き換えます。 基本的に、コンパイラは変数定義を見つけるたびに、いわゆるシンボルテーブルに名前を入れます。 少なくとも2つの列があります。名前(必要に応じて主キー)と場所です。 簡単に言うと、コンパイラがすべての変数を処理し、それらの場所を把握すると、コンパイラはすべての変数参照をそれぞれの場所と交換します。 (これには他にもありますが、それは資料に値する本です…​)

ポインタも_変数_です。 ポインターを便利にするのは、(ポインター)変数の場所に格納されているコンテンツを使用して、別の場所で値を読み書きできることです。 これは、ポインターの逆参照と呼ばれるものです。 これは、_run time_に行われます。 この点では、作業はコンパイル時から実行時まで延期されているため、変数が自動的に間接参照されるとは本当に言えません。


0


バディではないポインターは変数のセットであり、それらを区別するには、変数の数に加えて、値(整数、文字)が異なっていなければなりません!


0


変数は、保持するはずの値を保持するだけです。 ポインタの場合、メモリアドレスを保持し、整数の場合は整数値を保持し、浮動小数点数の場合は浮動小数点数を保持します…​


-2


変数は実際には何もしません。 代わりに、プログラムは変数に対して機能する場合があります。