あるサイトから読み込んでいるときに、レジスタ型のグローバル変数を作成できないと読みました。なぜそうなのですか? ソース: http://publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/index.jsp?topic=/com.ibm.xlcpp8l.doc/language/ref/regdef.htm
9 に答える
理論的には、プロセッサレジスタをグローバルスコープ変数に割り当てることができます。そのレジスタは、プログラムの存続期間中、その変数に割り当てられたままにする必要があります。
ただし、C コンパイラは通常、コンパイル段階でプログラム全体を確認することはできません。C 標準は、各翻訳単位(各ファイルにほぼ対応する.c
) を他の翻訳単位とは独立してコンパイルできるように記述されています (コンパイルされたオブジェクトは後でリンクされます)。プログラムに)。これが、グローバル スコープのレジスタ変数が許可されていない理由です。コンパイラがコンパイルしb.c
ているとき、コンパイラはレジスタに割り当てられたグローバル変数があったことを知る方法がありませんa.c
(したがって、関数はb.c
そのレジスタに値を保存する必要があります)。
実際、GCCはこれを許可しています。次の形式のグローバルスコープでの宣言:
register int foo asm ("r12");
レジスタ「r12」(x86_64上)をグローバル「foo」に割り当てます。これにはいくつかの制限があり、対応するマニュアルページは、おそらく、グローバルレジスタ変数が行うすべての面倒な作業への最良の参照です。
無意味でしょうから。グローバル変数は、アプリケーションが動作している間常に存在します。こんなに長い間、空いているプロセッサー・レジスターは確かにありません ;)
キーワードは、そのregister
名前が示すように見えるものとは異なる意味を持ちます。最近では、処理環境のレジスターとはあまり関係がありません。(おそらく一度はこのために選択されましたが。) で宣言された変数の使用を制限する唯一のテキストは、これですregister
。
単項 & 演算子のオペランドは、関数指定子、[] または単項 * 演算子の結果、またはビット フィールドではなく、レジスタ ストレージ クラス指定子で宣言されていないオブジェクトを指定する左辺値のいずれかでなければなりません。
そのため、そのような変数のアドレスを取得するとエラーになるように、自動変数 (関数で宣言するもの) に制限を実装します。その場合、コンパイラはこの変数を、レジスタやアセンブラの即時値など、好きなように表すことができるという考えです。プログラマは、そのアドレスを取得しないことを約束します。通常、これはグローバル変数にはあまり意味がありません (いずれにせよ、それらにはアドレスがあります)。
要約する:
- いいえ、
register
キーワードは無視されません。 - はい、標準に準拠したい場合は、スタック変数にのみ使用できます
本来、レジスタ変数はプロセッサ レジスタに格納されることを意図していましたが、グローバル変数は、すべての関数からアクセスできるようにデータまたは BSS セクションに格納する必要があります。register
現在、コンパイラはストレージ クラスを厳密に解釈しないため、主に互換性の理由からそのまま残されています。
レジスタワードは、変数のようなプロセッサのレジスタを使用するためのコンパイラへの要求として、C/C++ で使用されます。レジスタは、CPU によって使用される一種の変数であり、メモリ (RAM) に配置されていないため、アクセスが非常に高速です。レジスタの使用は、アーキテクチャとレジスタ自体のサイズによって制限されます (つまり、メモリ ポインタのようなものもあれば、特別なデバッグ値をロードするものもあります)。
C/C++ で使用される呼び出し規則は、パラメーターを保存するために汎用レジスター (80x86 Arch の EAX、EBX など) を使用しないため (ただし、戻り値は EAX に格納されます)、コードを高速化するレジスターのような var を宣言できます。 .
それをグローバルにしようとすれば、すべてのコードとすべてのソースのためにレジスターを予約するように頼むことになります。これは不可能であるため、コンパイラはエラーを返すか、単にメモリに格納されている通常の var にします。
一部のコンパイラは、レジスタを永続的に変数専用にする手段を提供します。ただし、register キーワードでは不十分です。ルーチンのローカル変数をレジスタに割り当てるというコンパイラの決定は、通常、他のソース モジュールとの調整を必要としません (一部の開発システムはルーチン間でレジスタの最適化を行いますが、呼び出し規則を定義するだけで、すべてのルーチンが特定のレジスタを自由に変更することが許可されています (したがって、呼び出し元は、関数呼び出し後に必要な場合に内容を保存する責任があります) が、他のものを変更してはなりません (したがって、呼び出されたルーチンは、レジスタが必要な場合に内容を保存および復元する責任があります)。したがって、リンカはレジスタの使用に関与する必要はありません。
このようなアプローチは、ローカル レジスタ変数には適していますが、グローバル レジスタ変数には役に立ちません。グローバル レジスタ変数を有効にするには、通常、プログラマは、どのレジスタをどの変数に使用するかをコンパイラに指示し、すべてのモジュールをコンパイルするときに、そのような予約がコンパイラに認識されるようにする必要があります。それ以外の場合は登録してください。これは、特に割り込みで使用される変数を使用する組み込みシステムで役立ちますが、通常、システムで使用できる変数の数は非常に限られています (たとえば 2 程度)。
それで、私たち全員が今同意しますか?グローバル変数をレジスタ変数にするのは、本当に悪い考えだと思いますか? 元の C の定義で禁止されていなかったとしたら、それはおそらく、誰も実際にそのように実装するとは考えていなかったからです。特に CISC の時代にはそうすべきではなかったからです。
その上、最新の最適化コンパイラは、変数をいつレジスタに保持するかを人間ができるよりもうまく決定します。あなたがそれを行うことができない場合は、本当に、より良いコンパイラを入手する必要があります。
彼らはレジスターにいるからです。言葉の矛盾です。