C の restrict キーワード

Abdul Mateen 2023年10月12日
  1. C でのコンパイラの最適化
  2. C の restrict キーワード
  3. C++ の restrict キーワード
  4. まとめ
C の restrict キーワード

このチュートリアルでは、C の restrict キーワードと、コンパイラの最適化におけるその使用について説明します。 したがって、最初にコンパイラの最適化について説明します。

次に、コード例を使用して C の restrict キーワードについて説明します。 最後に、C の restrict キーワードについて簡単に説明した後、結論を出します。

C でのコンパイラの最適化

コンパイラの重要な機能は、最適化のためのツールです。 一般に、コンパイラは高級言語プログラムを機械レベルのプログラムに変換すると考えられ、教えられています。

ただし、最新のコンパイラはコードの最適化も実行します。

コードの最適化により、実行時間、メモリ使用量、消費電力が最小限に抑えられます。 この行動は、文章を翻訳するだけでなく、文章をより良くするために修正する賢い翻訳者に似ています。

コンパイラーの最適化は、同等のコードを生成するための最適化変換で構成される非常に洗練されたプロセスであり、同じ出力を生成しますが、最小限のリソース (主に時間とストレージ) を消費します。

ここでは、コンパイラの最適化とその有用性を理解するための 1つの例を示します。 非常に単純なプログラムを考えてみましょう:

#include <stdio.h>
int main() {
  int i;
  for (i = 1; i <= 10; i++) printf("%d ", i);
  return 0;
}

出力:

1 2 3 4 5 6 7 8 9 10

これは非常に単純なプログラムです。 ただし、プログラムは、1 から 10 までのカウントを出力する以外に、いくつかの追加の手順を実行します。 比較ステップと増分ステップは少なくとも 10 回実行されます。 むしろ、比較は 11 回行われます (つまり、11 回目の反復では truefalse が 10 回)。

このカウントを出力するために、合計で 32 個のステートメントを使用します。 最初のステートメントは初期化です。

11 の比較ステートメント。 10 個のインクリメント ステートメントと 10 個の印刷ステートメント。

コンパイラは、上記のコードに含まれる定数を簡単に判断して、以下のコードのような同等のコードを生成できます。

#include <stdio.h>

int main() {
  printf("%d ", 1);
  printf("%d ", 2);
  printf("%d ", 3);
  printf("%d ", 4);
  printf("%d ", 5);
  printf("%d ", 6);
  printf("%d ", 7);
  printf("%d ", 8);
  printf("%d ", 9);
  printf("%d ", 10);
  return 0;
}

上記のコードの出力は、前のコードと同じです。 単一の print ステートメントでも同じ出力を生成できます。

これは単純な例です。 ただし、最新のコンパイラは、可能な限り多くのリソースを最小限に抑えるために、多くの高度な最適化を行っています。

C の restrict キーワード

C99 標準では restrict キーワードが導入されています。 このキーワードは、ポインターの宣言で型修飾子として使用されます。

新しい機能は追加されません。 ただし、コンパイラに特定の最適化を行うように通知するためにのみ使用されます。

このキーワードはポインターと共に使用され、これが変数/メモリーを使用する唯一のポインターであり、他のポインターが同じメモリーにアクセスしていないことをコンパイラーに通知します。

これは役に立たない情報のようです。 ただし、このコンパイラーには、他のポインターが同じメモリーにアクセスしていないことが通知されます。 したがって、メモリのロード/アンロードに追加のチェックを適用する必要はありません。

restrict キーワード構文

restrict キーワードは、* の後、変数名の前にポインター宣言と共に追加されます。

int* restrict x;

明らかに、このキーワードはコードの機能には影響しません。 したがって、コードで restrict キーワードを使用する方法を説明する 1つの例を示します。

#include <stdio.h>

void f1(int *a, int *restrict b) { printf("%d %d\n", *a, *b); }
int main() {
  int x = 100, y = 200;
  f1(&x, &y);
  return 0;
}

このコードでは、restrict キーワードが、関数 f1 の 2 番目のパラメーターを持つ修飾子として追加されています。

このキーワードは、このポインターによってアクセスされるメモリーが排他的であり、他のポインターが同じメモリーにアクセスしないことをコンパイラーに伝えます。 したがって、コンパイラはアセンブリ コードを単純に保つことで最適化を行うことができます。

出力:

100 200

ここでも、restrict キーワードを削除しても、出力は同じままです。

C++ の restrict キーワード

驚くべきことに、C++ では restrict キーワードを使用できないことに注意することも重要です。

あなたはそれをググることができます。 ただし、これは C++ がこの機能をサポートしていないという意味ではありません。 C++ には暗黙的にこの機能があり、コンパイラにはこのタイプの制限を自動的に識別する方法があり、それに応じて最適化が実行されます。

まとめ

コンパイラは、リソースを最適化するためにコードの最適化を追加します。 restrict は、コンパイラがより適切な最適化の決定を行うのに役立つフラグです。

restrict キーワードは、C99 より前の C 言語ではサポートされていませんでした。 このキーワードは機能を追加しません。 むしろ、このメモリアクセスが排他的で制限されていることをコンパイラに通知します。 したがって、コンパイラは、ターゲットの変換されたアセンブリ コードで必要な最適化を実行します。

restrict キーワードの有無にかかわらず、コードの機能に違いはありません。 最後に、C++ はこのキーワードを明示的にサポートしていません。