キーワードではない(または別の名前のコメント) byHerb Sutter
そうです、一部のキーワードは、意味的には空白、栄光に満ちたコメントと同等です。
そして
C++言語がキーワードを予約語として扱う理由を見てきました。また、C++プログラムにセマンティックな違いをもたらさない2つのキーワード(autoとregister)を見てきました。それらを使用しないでください。とにかくそれらは単なる空白であり、空白を入力するより速い方法があります。
auto
(C++ 11ではないかもしれません)やregister
のようなキーワードに値がない場合、なぜそれらが作成され使用されたのですか?
変数の前にregister
を含めても違いがない場合
#include<stdio.h>
int main(){
register int a = 15;
printf("%d\n%d\n",&a,a);
return 0;
}
上記のプログラムでエラーが発生するのはなぜですか?
test_register.c:関数「main」内:
test_register.c:4:2:エラー:レジスタ変数「a」のアドレスが要求されました
printf( "%d\n%d\n"、&a、a);
次のプログラムはC++で動作します。
#include<iostream>
int main(){
register int a = 15;
std::cout<<&a<<'\n'<<a;
return 0;
}
Cでは、register
ストレージクラスがコンパイラへのヒントとして使用され、 変数はレジスタに優先的に格納される必要がある であることを表現しました。 register
変数を実際のレジスタに保存するヒントは尊重される場合とされない場合がありますが、どちらの場合でも関連する制限が適用されることに注意してください。 C11、6.7.1p6(強調鉱山)を参照してください:
ストレージクラス指定子
register
を使用したオブジェクトの識別子の宣言は、オブジェクトへのアクセスが可能な限り高速であることを示唆しています。 そのような提案が効果的である範囲は実装定義です。[脚注121][脚注121]実装は、任意の
register
宣言を単にauto
宣言として扱うことができます。 ただし、アドレス可能なストレージが実際に使用されているかどうかにかかわらず、ストレージクラス指定子register
で宣言されたオブジェクトの任意の部分のアドレスは計算できません、明示的に(6.5.3.2で説明した単項&演算子を使用)または暗黙的に(6.3.2.1で説明したように配列名をポインターに変換して)。したがって、ストレージクラス指定子register
で宣言された配列に適用できる演算子は、sizeof
と_Alignof
。
C++では、単に未使用の予約キーワードですが、Cコードとの構文上の互換性のために保持されていると想定するのは合理的です。
Cでは、auto
ストレージクラスは自動ストレージの変数を定義しますが、 関数ローカル変数はデフォルトでauto
なので、通常は使用されません。
同様に、構文上の互換性のためだけに最初にC++に引き継がれたと仮定するのは合理的です。ただし、後で独自の意味を持ちます( type inference )。
Cのregister
は2つの目的を果たしました。
これはconst
に似ています。
例として、この単純な関数を考えてみましょう:
_int sum(const int *values, size_t length) {
register int acc = 0;
for (size_t i = 0; i < length; ++i) {
acc += values[i];
}
return acc;
}
_
プログラマーはregister
を記述して、アキュムレーターをスタックから切り離し、更新されるたびにメモリーが書き込まれるのを防ぎます。実装が次のように変更された場合:
_// Defined in some other translation unit
void add(int *dest, int src);
int sum(const int *values, size_t length) {
register int acc = 0;
for (size_t i = 0; i < length; ++i) {
add(&acc, values[i]);
}
return acc;
}
_
acc
変数は、アドレスがadd()
呼び出しに使用されたときにレジスタに格納できなくなりました。これは、レジスタにアドレスがないためです。したがって、コンパイラーは_&acc
_をエラーとしてフラグ付けし、acc
がレジスターに存在しないようにしてコードのパフォーマンスを破壊した可能性があることを知らせます。
これは、コンパイラーが無力で、関数全体で変数が1か所に存在する初期の頃にはずっと重要でした。今日では、変数はそのアドレスの取得時に一時的にスタックに移動されるだけで、その寿命の大部分をレジスタで費やすことができます。つまり、次のコード:
_/* Passed by reference for some reason. */
void debug(const int *value);
int sum(const int *values, size_t length) {
int acc = 0;
for (size_t i = 0; i < length; ++i) {
acc += values[i];
}
debug(&acc);
return acc;
}
_
古いコンパイラでは、acc
が関数全体のスタック上に存在することになります。最新のコンパイラは、debug()
呼び出しの直前までacc
をレジスタに保持します。
最近のCコードでは、通常register
キーワードを使用しません。
C99の根拠は、キーワードregister
のコンテキストをさらに提供します。
国際標準の根拠—プログラミング言語— C
§6.7.1ストレージクラス指定子
register
変数のアドレスを取得できないため、ストレージクラスregister
のオブジェクトは、他のオブジェクトとは異なるスペースに効果的に存在します。 (関数はさらに3番目のアドレス空間を占有します。)これにより、レジスタを宣言する通常の理由である最適な配置の候補になります。しかし、より積極的な最適化の候補にもなります。