参考までに、restrict
修飾子のかなり複雑な定義を次に示します(C99 6.7.3.1「制限の正式な定義」から)。
Dを、オブジェクトPをタイプTへの制限修飾ポインターとして指定する手段を提供する通常の識別子の宣言とします。
Dがブロック内に表示され、ストレージクラスexternがない場合は、Bがブロックを示します。関数定義のパラメーター宣言のリストにDが表示されている場合は、Bが関連するブロックを示しているとします。それ以外の場合は、Bがメインのブロック(または自立環境でのプログラムの起動時に呼び出される関数のブロック)を示します。
以下では、ポインタ式Eは、(Eの評価前のBの実行のあるシーケンスポイントで)以前にポイントした配列オブジェクトのコピーを指すようにPを変更する場合、オブジェクトPに基づくと言われます。 Eの値を変更します。「based」はポインタ型の式に対してのみ定義されていることに注意してください。
Bを実行するたびに、LをPに基づく&Lを持つ任意の左辺値とします。Lが指定されたオブジェクトXの値にアクセスするために使用され、Xも(何らかの方法で)変更される場合、次の要件が適用されます。 :Tはconst-qualifiedであってはなりません。Xの値にアクセスするために使用される他のすべての左辺値も、Pに基づくアドレスを持つものとします。Xを変更するすべてのアクセスは、この節の目的のために、Pを変更することも考慮されるものとします。ブロックB2に関連付けられた別の制限付きポインタオブジェクトP2に基づくポインタ式Eの値がPに割り当てられている場合、B2の実行はBの実行の前に開始するか、B2の実行はBの実行の前に終了する必要があります。割り当て。これらの要件が満たされていない場合、動作は未定義です。
ここで、Bの実行とは、プログラムの実行のうち、Bに関連付けられたスカラー型と自動ストレージ期間を持つオブジェクトの存続期間に対応する部分を意味します。
上記を読んだことは、最初の質問では、「子」ブロック内であっても、a
に割り当てることができないことを意味します。結果は未定義です。その「サブブロック」で宣言されてb
いれば、そのような割り当てを行うことができますが、と同じスコープで宣言されているため、割り当てを行うことはできません。b
b
a
質問2の場合、との間の割り当てc
によりd
、未定義の動作が発生します(どちらの場合も)。
標準の関連ビット(両方の質問)は次のとおりです。
ブロックB2に関連付けられた別の制限付きポインタオブジェクトP2に基づくポインタ式Eの値がPに割り当てられている場合、B2の実行はBの実行の前に開始するか、B2の実行はBの実行の前に終了する必要があります。割り当て。
制限付きポインターは同じブロックに関連付けられているため、ブロックB2をBの実行前に開始したり、B2を割り当て前に終了したりすることはできません(BとB2は同じブロックであるため)。
この標準は、これをかなり明確にする例を示しています(restrict
定義の4つの短い段落の明確さは、C ++の名前解決規則と同等です)。
例4:
制限されたポインター間の割り当てを制限するルールは、関数呼び出しと同等のネストされたブロックを区別しません。1つの例外を除いて、ネストされたブロックで宣言された制限付きポインター間の「外部から内部へ」の割り当てのみが動作を定義します。
{
int * restrict p1;
int * restrict q1;
p1 = q1; // undefined behavior
{
int * restrict p2 = p1; // valid
int * restrict q2 = q1; // valid
p1 = q2; // undefined behavior
p2 = q2; // undefined behavior
}
}