6

インデックスを計算して2番目の関数に渡す大きな配列があるとします。簡単な例として、次のようなものがあります。

void foo(float* array, float c, unsigned int n)
{
    for (unsigned int i = 0; i < n; ++i)
        array[i] *= c;
}

void bar(float* restrict array, float* restrict array2, unsigned int m, unsigned int n)
{
    for (unsigned int i = 0; i < m; ++i)
        foo(&array[i * n], array2[i], n);
}

これは、配列の一部のアドレスを foo() に渡す、bar() 内の配列の一部のエイリアスを実際に使用したことがない場合でも、bar() の制限の規則に違反していますか?

4

2 に答える 2

9

(すべての引用は、C99 に技術的な正誤表 (TC3) を加えたN1256を参照しています。)

の正式な定義はrestrict、§6.7.3.1 に記載されています。以下に最も重要な節を引用します。スコープが block であるtype へPrestrict修飾されたポインターです。ポインター式は、それが指す値ではなく、それ自体の値に依存する場合に基づいていると言われます。TBE PPP

を実行するたびにB、P に基づくL任意の左辺値をとします。が指定するオブジェクトの値にアクセスするために使用され、 (何らかの方法で) 変更される場合は、次の要件が適用されます。&LLXX

  • Tconst 修飾されてはなりません。
  • の値にアクセスするために使用される他のすべての左辺値Xも、 に基づくアドレスを持つものとしPます。
  • 変更するすべてのアクセスは、この節の目的のために、X変更とも見なされるものとします。P
  • block に関連付けられた別の制限付きポインター オブジェクト に基づくPポインター式の値が に割り当てられた場合、の実行はの実行前に開始されるか、 の実行は代入の前に終了します。EP2B2B2BB2

これらの要件が満たされない場合、動作は未定義です。


barのの部分へarrayのアクセスについてルールが何を述べているかを見てみましょうfooarrayのパラメーター リストで宣言された制限修飾ポインターであるから始めますbar。わかりやすくするために、次のパラメータをアルファ変換しますfoo

void foo(float* b, float c, unsigned int n) { /*modify b[i]*/ }

が指すストレージarrayも、 によって変更されますb。2 番目の箇条書きは(§6.5.3.2 を参照)&array[i*n]に相当するので問題ありません。array+(i*n)

bが restrict-qualified だった場合P、 ← bBfooP2arrayB2←で 4 番目の箇条書きをチェックする必要がありbarます。B内部にネストされているためB2(関数はここでインライン化されているかのように動作します。§6.7.3.1.11 を参照してください)、最初の条件が満たされます。3 番目の箇条書き ( へのアクセス) の 1 つのインスタンスもありますがb[i]fooこれは問題ではありません。

ただしb、restrict 修飾されていません。§6.3.2.3.2 によると、「任意の修飾子qについて、非q修飾型へのポインターは、その型のq修飾バージョンへのポインターに変換される可能性があります。元のポインターと変換されたポインターに格納されている値は、等しいものと比較されます。」したがって、 からarray+(i*n)への変換bは明確に定義され、明確な意味を持つため、プログラムの動作が定義されます。さらに、brestrict修飾されていないため、線形条件に従う必要はありません。たとえば、次fooは と組み合わせて使用​​できbarます。

void qux(float *v, float *w) {
    v[0] += w[0];
}
void foo(float* b, float c, unsigned int n)
{
    qux(b,b);
}

追加: 「配列の一部のアドレスを foo() に渡す bar() 内」の特定の懸念に対処するために、これは問題ではありません:restrict配列ではなくポインターに適用され、演算を実行できますそれ(箇条書き2)。

于 2010-10-04T19:48:14.510 に答える
-2

いいえ、restrict は配列がエイリアスを作成できないことを意味するため、ルールを破ることなく bar に何かを渡すことができます

于 2010-10-04T16:33:04.790 に答える