5

レジスタ変数の概念とその使用例は知っていますが、私が試したことに基づいて、いくつかの疑問が頭に浮かびます。

  1. Cではレジスタ変数のアドレスにアクセスできますが、C++ではアクセスできません! なんで?レジスタ変数のアドレッシングへのアクセスに問題はありますか?

  2. C++ で文字列変数をレジスタとして宣言した場合、その変数はどこに格納されるでしょうか? C++ で「文字列」などの非数値データ型のストレージ クラスをレジスタとして宣言するポイントは何ですか??

更新: 次のようなプログラムでエラーが発生しなかったため、C++ を使用するとレジスタ変数のアドレスをフェッチできると思いました。

#include<iostream>
#include<time.h>

using namespace std;

clock_t beg, en;

int main(){

    int j, k=0;

    beg=clock();
    for(register int i=0;i<10000000;i++){
        /*if(k==0){
            cout<<&i<<endl;    // if this code is uncommented, then C++ rejects the recommendation to make 'i' as register
            k++;
        }*/
    }
    en=clock();

    cout<<en-beg<<endl;

    cout<<&j<<endl<<&k;

    return 0;
}

私が観察したことは、変数「i」をレジスタとして作成し、「&i」を使用してアドレスを出力しようとしない場合、C++ は推奨事項を受け入れ、「i」をレジスタに格納します。これは実行時間から推測できます「i」がレジスタにある場合、ループは常に約 4 ~ 12 ミリ秒になります。しかし、変数 'i' のアドレスを出力しようとすると、エラーは発生しませんが、C++ は推奨事項を拒否します。これは、i が登録されていない場合は常に 25 を超えるループの実行時間から推測できます。 !

したがって、基本的に、C と C++ の両方で、記憶域クラスを持つ変数のアドレスをレジスタとしてフェッチすることはできません!! なぜ?

4

8 に答える 8

8

まず、関連する規格を見てみましょう。C と C++ でこのキーワードの意味が異なる可能性は常にあります。

C++ 2011 セクション 7.1.1 パラグラフ 2 および 3:

レジスタ指定子は、ブロックで宣言された変数の名前 (6.3) または関数パラメーター (8.4) にのみ適用されます。名前付き変数に自動保存期間があることを指定します (3.7.3)。ブロック スコープで storage-class-specifier なしで宣言された変数、または関数パラメーターとして宣言された変数には、既定で自動ストレージ期間があります。

レジスタ指定子は、そのように宣言された変数が頻繁に使用されるという実装へのヒントです。[ 注: ヒントは無視できます。ほとんどの実装では、変数のアドレスが取得された場合は無視されます。この使用は非推奨です (D.2 を参照)。— エンドノート]

C 2011 セクション 6.7.1 パラグラフ 6 および脚注 121:

ストレージ クラス指定子 register を使用したオブジェクトの識別子の宣言は、オブジェクトへのアクセスが可能な限り高速であることを示唆しています。そのような提案が有効である範囲は、実装によって定義されます。)

実装では、任意のレジスタ宣言を単純に auto 宣言として扱うことができます。ただし、アドレス可能な記憶域が実際に使用されているかどうかにかかわらず、記憶域クラス指定子 register で宣言されたオブジェクトのどの部分のアドレスも、明示的に (6.5.3.2 で説明したように単項 & 演算子を使用して) 計算することも、暗黙的に計算することもできません ( 6.3.2.1 で説明されているように、配列名をポインターに変換することによって)。したがって、ストレージ クラス指定子 register で宣言された配列に適用できる演算子は、sizeof と _Alignof だけです。

それでは、ここで学んだことを取り上げましょう。

  • C++ では、register キーワードは意味を持ちません。これはコンパイラのヒントとして機能しますが、ほとんどのコンパイラはとにかくそのヒントを無視することをお勧めします。
  • C では、register キーワードは意味を保持します。ここでは、たとえば、オブジェクトのアドレスを取得することは許可されていません (引用された脚注を参照)。実装はレジスタ ヒントを無視し、とにかくオブジェクトをメモリに配置することができますが、キーワードはオブジェクトでできることを制限します。これらの制限により、コンパイラはオブジェクトへのアクセスをより適切に最適化できるようになりますが、(C++ の場合に示唆されているように) コンパイラがとにかくこれを推測できる可能性もあります。

あなたが実際に見ているものについて:

  • C で a のアドレスを取得しようとすると構文エラーが発生する理由がわかりますregister int
  • を使用するかどうかに応じて、C++ でパフォーマンスの違いが見られると主張していますregister。この場合、テスト自体に問題がある可能性があるため、テストを表示することをお勧めします。完全なテストに問題がない場合、コンパイラがヒントを使用してより良いコードを生成している可能性は確かにあります。
  • あなたが示したコードは確かに奇妙です。これは、最適化されたコンパイラが for ループ全体をコードから削除する可能性が高いためです。for ループには副作用がありません。コンパイラが および と同一のコード (つまり、コードなし) を返す可能性が高く (そして好ましい)for (int i=0; i<100; ++i){}ですfor (register int i=0; i<100; ++i) {}
于 2013-07-09T23:36:11.953 に答える