web-dev-qa-db-ja.com

Cでのレジスタ変数の使用法の良い例は何ですか?

私はK&Rを読んでいて、レジスター変数に関する小さなセクションに行きました。そして、ここの人々がこれのいくつかの良い例を実践しているかどうか疑問に思いました。

K&Rのセクション4.7から:

レジスタ宣言は次のようになります
register int x;
register char c;

明確にするために、私はいくつかのクールなコードサンプルを見たいと思っています。私は(私が)主題を理解しているので、(必要な場合を除いて)詳細な説明を入力する必要を感じないでください。

32
Kyle Walsh

最新のコンパイラー(過去15年以上を読む)を使用する場合のレジスターの使用の良い例はありません。なぜなら、それはほとんど何の役にも立たず、いくらか悪いことをする可能性があるからです。 registerを使用すると、コンパイラに「コードを最適化する方法をあなたよりもよく知っている」と言っていることになりますが、これはほとんどありません。 registerを使用すると、次の3つのいずれかが発生する可能性があります。

  • コンパイラはそれを無視します、これはおそらくそうです。この場合の唯一の害は、コード内の変数のアドレスを取得できないことです。
  • コンパイラーは要求を受け入れ、その結果、コードの実行速度が低下します。
  • コンパイラーは要求を受け入れ、コードはより高速に実行されます。これは最も可能性の低いシナリオです。

Registerを使用すると、あるコンパイラがより優れたコードを生成したとしても、別のコンパイラが同じことを行うと信じる理由はありません。コンパイラが十分に最適化していない重要なコードがある場合、最善の策はおそらくその部分にアセンブラを使用することですが、もちろん、生成されたコードが本当に最初に問題であることを確認するために適切なプロファイリングを行います。

69
Robert Gamble

一般的に私は Robert に同意しますが、良いルールとしてこれにも例外があります。
深く埋め込まれたシステムで作業している場合は、特定のハードウェアアーキテクチャ上の特定のアプリケーションのコードを最適化する方法をコンパイラよりもよく知っているかもしれません

しかし、99%の場合、Robertsの説明は埋め込みWordにも適しています。

12
Ilya

これはかなり前からのことですが、これはヒープソートからのサブプロシージャの実装です。レジスタ変数を使用すると、少なくともgcc 4.5.2を使用してコードをコンパイルすると、アルゴリズムが高速になります。

inline  void max_heapify(int *H, int i){
    char OK = FALSE;
    register int l, r, max, hI;
    while(!OK){
        OK = TRUE;
        l = left(i);
        r = right(i);
        max = i;
        if(l <= H[SIZE] && H[l] > H[i]){
            max = l;
        }
        if(r <= H[SIZE] && H[r] > H[max]){
            max = r;
        }
        if(max != i){
            OK = FALSE;
            hI = H[i];
            H[i] = H[max];
            H[max] = hI;
            i = max;
        }
    }
}

属性の前にregisterキーワードがある場合とない場合のアルゴリズムをテストし、それを実行して、ノートブック上の50,000,000要素のランダム配列をバージョンごとに数回並べ替えました。

レジスターを使用すると、ヒープソート時間が約135秒から約125秒に短縮されました。

また、5,000,000要素のみでテストしましたが、さらに何度も実行しました。

レジスタのないバージョンは11秒で開始しましたが、実行するたびに9,65秒に達するまで時間が短縮され、そこで停止しました。

レジスター付きのバージョンは10秒で始まり、8,80秒まで時間を短縮しました。

キャッシュメモリと関係があると思います。それにもかかわらず、レジスタは一定の要因によってアルゴリズムを高速化するようです

これらの変数はアルゴリズムに沿って非常によく使用されるため、この作業をコンパイラーに任せるのではなく、レジスターにあることを確認することで、この場合の結果が向上しました。しかし、それはそれほど時間を改善しませんでした。

うまくいけば、thillは誰か、挨拶に役立つでしょう。

4
Rafael

もう1つの一般的なケースは、低レベルのインタープリターを実装する場合です。レジスタにいくつかの状態を保持します。仮想マシンスタックポインタは、メモリアクセスを大幅に削減し、コードを高速化できます。

最適化の例については、 vmgen —効率的な仮想マシンインタープリターのジェネレーター を参照してください(5.2スタックキャッシュのトップ)。

3
Hrvoje Prgeša

まず、レジスタ変数は、アクセス時間を最小限に抑えてパフォーマンスを向上させるために、ループ制御変数などの頻繁に使用される変数に使用する必要があります。二次的に使用できるのは、fun(auto int a、auto int b):error fun(register int a、register int b):rightこれだけが実行されるfun(static int a、 static int b):error fun(extern int a、extern int b):error

1
Ashutosh Tiwari

これは、複数のコーディングコンテキストがあるため、複数の回答が必要な質問です。C言語はアセンブリルーチンを呼び出すことができるため、高水準言語の観点から、中レベルおよび低レベル(アセンブリまで)です。

Cの代わりにAssemblyを使用する理由は、開発中に発生したパフォーマンスの問題のためです。はい、registerキーワードが必要ですが、多くの場合、開発者が意図したとおりに機能していません。

0
yan bellavance