レジスタ変数の格納に関するポイントについて説明したいのですが、コードでレジスタ変数を宣言した場合に、それがレジスタにのみ格納されるようにする方法はありますか?
#include<iostream>
using namespace std;
int main()
{
register int i=10;// how can we ensure this will store in register only.
i++;
cout<<i<<endl;
return 0;
}
できません。変数が頻繁に使用されていることを示唆するのは、コンパイラーへのヒントにすぎません。 C99の文言は次のとおりです。
ストレージクラス指定子
register
を持つオブジェクトの識別子の宣言は、オブジェクトへのアクセスが可能な限り高速であることを示しています。そのような提案が効果的である程度は、実装によって定義されます。
そして、これがC++ 11の文言です。
register
指定子は、そのように宣言された変数が頻繁に使用されるという実装へのヒントです。 [注:ヒントは無視できます。ほとんどの実装では、変数のアドレスが取得された場合、ヒントは無視されます。この使用は非推奨です(D.2を参照)。 —エンドノート]
実際、register
ストレージクラス指定子はC++ 11(付録D.2)で非推奨になりました。
storage-class-specifier(7.1.1)としての
register
キーワードの使用は非推奨です。
レジスタにはアドレスがないため、Cではregister
変数のアドレスを取得できないことに注意してください。この制限はC++で削除され、アドレスを取得することで、変数がレジスターに格納されないことがほぼ保証されます。
最近のコンパイラの多くは、C++のregister
キーワードを単に無視します(もちろん、無効な方法で使用されている場合を除きます)。それらは、register
キーワードが有用だったときよりも最適化がはるかに優れています。ニッチなターゲットプラットフォーム用のコンパイラは、それをもっと真剣に扱うことを期待しています。
register
キーワードは、CとC++で異なる意味を持っています。 C++では、実際には冗長であり、最近では非推奨になっているようです。
Cでは違います。まず、キーワードの名前を文字通りとらないでください。最近のCPUの「ハードウェアレジスタ」とは必ずしも関係がありません。 register
変数に課せられる制限は、それらのアドレスを取得できないことです。&
操作は許可されていません。これにより、最適化のために変数をマークし、そのアドレスを取得しようとした場合にコンパイラーが確実に叫ぶようにすることができます。特に、register
修飾されたconst
変数はエイリアスを作成できないため、最適化の候補として適しています。
Cのようにregister
を使用すると、変数のアドレスを取得するすべての場所を体系的に考える必要があります。これはおそらく、オブジェクトやそのようなものへの参照に大きく依存しているC++でやりたいことではありません。これが、C++がregister
変数のこのプロパティをCからコピーしなかった理由である可能性があります。
一般的にそれは不可能です。具体的には、確率を高めるために特定の対策を講じることができます。
適切な最適化レベルを使用します。 -O2
変数の数を少なくしてください
register int a,b,c,d,e,f,g,h,i, ... z; // can also produce an error
// results in _spilling_ a register to stack
// as the CPU runs out of physical registers
レジスタ変数のアドレスを取得しないでください。
register int a;
int *b = &a; /* this would be an error in most compilers, but
especially in the embedded world the compilers
release the restrictions */
一部のコンパイラでは、提案することができます
register int a asm ("eax"); // to put a variable to a specific register
これはコンパイラへの単なるヒントです。 force変数をレジスタに配置することはできません。いずれにせよ、コンパイラーの作成者は、アプリケーションプログラマーよりもターゲットのアーキテクチャーについての知識が豊富であるため、レジスタ割り当ての決定を行うコードを作成するのに適しています。つまり、register
を使用しても何も達成できない可能性があります。
「register」キーワードは、コンパイラが2MBのRAM(それぞれにログインしているユーザーがいる18台の端末間で共有)またはPC /ホームコンピュータに適合しなければならなかった時代の名残です。 128〜256KBのRAMを搭載。その時点で、コンパイラは大きな関数を実行して、どのレジスタをどの変数に使用するかを判断し、レジスタを最も効果的に使用することができませんでした。したがって、プログラマが「ヒント」を与えた場合register
、コンパイラはそれをレジスタに入れます(可能な場合)。
最新のコンパイラは、2MBのRAMに数回は収まりませんが、レジスタに変数を割り当てるのにはるかに優れています。与えられた例では、コンパイラがそれをレジスタに入れないのは非常に不愉快だと思います。明らかに、レジスターの数は限られており、十分に複雑なコードが与えられると、一部の変数はレジスターに収まりません。しかし、そのような単純な例では、最新のコンパイラーはi
をレジスターにし、おそらくostream& ostream::operator<<(ostream& os, int x)
内のどこかまでメモリにアクセスしません。
レジスタを使用していることを確認する唯一の方法は、インラインアセンブリを使用することです。ただし、これを行っても、コンパイラがインラインアセンブリブロックの値outsideを格納しないという保証はありません。そしてもちろん、OSは、CPUを別のプロセスに渡すために、いつでもプログラムを中断して、すべてのレジスタをメモリに格納することを決定する場合があります。
したがって、すべての割り込みを無効にしてカーネル内にアセンブラコードを記述しない限り、変数がメモリにヒットしないことを保証する方法はまったくありません。
もちろん、それはあなたが安全を心配している場合にのみ関係があります。パフォーマンスの観点から、通常は-O3
を使用してコンパイルするだけで十分です。コンパイラーは通常、レジスターに保持する変数を決定するのに非常に優れています。とにかく、変数をレジスターに格納することは、パフォーマンスチューニングの1つの小さな側面にすぎません。はるかに重要な側面は、内部ループで余分な作業や高価な作業が行われないようにすることです。
一般に、CPPコンパイラ(g ++)は、コードに対してかなりの数の最適化を行います。したがって、レジスタ変数を宣言するときに、コンパイラがその値をレジスタに直接格納する必要はありません。 (つまり、コード 'register int x'は、コンパイラがそのintをレジスタに直接格納しない場合があります。しかし、コンパイラーにそうさせることができれば、成功する可能性があります。
たとえば、次のコードを使用する場合、コンパイラに必要な処理を強制することができます。次のコードのコンパイルはエラーになる可能性があります。これは、intが実際にレジスタに直接格納されていることを示しています。
int main() {
volatile register int x asm ("eax");
int y = *(&x);
return 0;
}
私の場合、この場合、g ++コンパイラは次のエラーをスローします。
[nsidde@nsidde-lnx cpp]$ g++ register_vars.cpp
register_vars.cpp: In function ‘int main()’:
register_vars.cpp:3: error: address of explicit register variable ‘x’ requested
行 'volatile register int x asm( "eax")'は、整数xを 'eax'レジスタに格納し、その際に最適化を行わないようにコンパイラに指示しています。これにより、値がレジスタに直接格納されるようになります。そのため、変数のアドレスにアクセスするとエラーがスローされます。
または、Cコンパイラ(gcc)が次のコード自体でエラーになる場合があります。
int main() {
register int a=10;
int c = *(&a);
return 0;
}
私の場合、この場合、gccコンパイラは次のエラーをスローします。
[nsidde@nsidde-lnx cpp]$ gcc register.c
register.c: In function ‘main’:
register.c:5: error: address of register variable ‘a’ requested
ここでは、C++でvolatile register int i = 10
を使用して、i
がレジスタに格納されるようにすることができます。 volatile
キーワードは、コンパイラが変数i
を最適化することを許可しません。