12

コードのどこかで変数のアドレスを使用する場合 (たとえば、他の関数に渡す場合)、コンパイラは自動的にそれをメモリに格納することを選択しますか? (レジスタに格納する可能性とは対照的に)。

そうでなければ、そのような変数 (レジスタとして格納されている) のアドレスを要求するとどうなりますか? register ( ) に明示的に設定された変数のアドレスを取得できないことはわかっていますregister int c

編集

たとえば、次のようなことをすると

int c = 1;
print("Address of c: %p", &c);

では、この変数はレジスタに格納できませんでしたね。コンパイラはメモリに格納されているように自動的に設定しますか? それ以外の場合 (単にレジスタに格納されている場合)、画面に表示されるアドレスは何でしょうか?

4

3 に答える 3

19

まず、C 標準では、宣言された変数のアドレスを取得することを禁止しています。これは、s のregisterビット フィールドの場合と同様ですstruct

非登録 (「自動」) 変数の場合、短い答えは「はい」です。オプティマイザの最も単純な戦略は、アドレスが取得された変数をすぐにスピルすることです。

「スピル」は、レジスタ割り当ての文献からの用語であり、「レジスタではなくメモリに配置することを決定する」ことを意味します。

洗練されたオプティマイザーは、アドレスが取得されたとしても、エイリアス分析を実行し、レジスターに値を保持することができます。これは、結果のポインターを使用して値を変更できない可能性があることが証明できる場合はいつでも可能です。

関連するもう 1 つの最適化は、ライブ範囲分割です。これにより、変数が有用な値を保持している命令範囲の一部 (「ライブ範囲」) のレジスタに変数を格納し、他の部分にスピルすることができます。この場合、こぼれた部分は、ポインターを使用して変数の値を変更できる場所に対応します。例えば:

x = 3;
... lots of computations involving x
if T {
  // SPILL HERE, so store register holding x to memory
  int *p = &x;
  ... lots of computations, perhaps using p to change x
  *p = 2;
  // DONE SPILL HERE, so reload register
  ... more code here not using p to change x.
}
else {
  ... lots of computations involving x.
}

このコードの積極的なオプティマイザーは、x のスタック位置を割り当てる可能性がありますが、それをコードの上部にあるレジスターにロードし、SPILL としてマークされた領域を除いてそこに維持します。この領域は、メモリへのレジスタのストアと一致するレジスタのロードによって囲まれます。

于 2013-05-20T03:53:07.720 に答える
3

そのアドレスを取得することにより、コンパイラに変数をメモリに配置させ、レジスタに最適化させないようにします。

この回答にはいくつかの良い情報があります:レジスタ変数のアドレス

于 2013-05-20T03:52:30.393 に答える
0

コンパイラはポインタの最適化に細心の注意を払う必要があります。これが、次のような最適化キーワードがrestrict存在する理由です (ポインターの他のコピーがどこにもないことをコンパイラーに伝えます)。したがって、通常、あなたが説明する状況はありません。

于 2013-05-20T03:53:05.837 に答える