(すべての引用は、C99 に技術的な正誤表 (TC3) を加えたN1256を参照しています。)
の正式な定義はrestrict
、§6.7.3.1 に記載されています。以下に最も重要な節を引用します。スコープが block であるtype へP
のrestrict
修飾されたポインターです。ポインター式は、それが指す値ではなく、それ自体の値に依存する場合に基づいていると言われます。T
B
E
P
P
P
を実行するたびにB
、P に基づくL
任意の左辺値をとします。が指定するオブジェクトの値にアクセスするために使用され、 (何らかの方法で) 変更される場合は、次の要件が適用されます。&L
L
X
X
T
const 修飾されてはなりません。
- の値にアクセスするために使用される他のすべての左辺値
X
も、 に基づくアドレスを持つものとしP
ます。
- 変更するすべてのアクセスは、この節の目的のために、
X
変更とも見なされるものとします。P
- block に関連付けられた別の制限付きポインター オブジェクト に基づく
P
ポインター式の値が に割り当てられた場合、の実行はの実行前に開始されるか、 の実行は代入の前に終了します。E
P2
B2
B2
B
B2
これらの要件が満たされない場合、動作は未定義です。
bar
のの部分へarray
のアクセスについてルールが何を述べているかを見てみましょうfoo
。array
のパラメーター リストで宣言された制限修飾ポインターであるから始めます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
、 ← b
、B
← foo
、P2
← array
、B2
←で 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
は明確に定義され、明確な意味を持つため、プログラムの動作が定義されます。さらに、b
はrestrict
修飾されていないため、線形条件に従う必要はありません。たとえば、次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)。