5

制限付きポインタに関する規則について少し混乱しています。多分そこに誰かが私を助けることができます。

  1. ネストされた制限付きポインターを次のように定義することは合法ですか?

    int* restrict a;
    int* restrict b;
    
    
    a = malloc(sizeof(int));
    
    
    // b = a; <-- assignment here is illegal, needs to happen in child block
    // *b = rand();
    
    
    while(1)
    {
        b = a;  // Is this legal?  Assuming 'b' is not modified outside the while() block
        *b = rand();
    }
    
  2. 次のように制限付きポインタ値を導出することは合法ですか?

    int* restrict c;
    int* restrict d;
    
    
    c = malloc(sizeof(int*)*101);
    d = c;
    
    
    for(int i = 0; i < 100; i++)
    {
        *d = i;
        d++;
    }
    
    
    c = d; // c is now set to the 101 element, is this legal assuming d isn't accessed?
    *c = rand();
    

ありがとう!アンドリュー

4

2 に答える 2

4

参考までに、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いれば、そのような割り当てを行うことができますが、と同じスコープで宣言されているため、割り当てを行うことはできません。bba

質問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
    }
}
于 2010-09-27T04:05:08.497 に答える
1

The restrict type qualifier is an indication to the compiler that, if the memory addressed by the restrict-qualified pointer is modified, no other pointer will access that same memory. The compiler may choose to optimize code involving restrict-qualified pointers in a way that might otherwise result in incorrect behavior. It is the responsibility of the programmer to ensure that restrict-qualified pointers are used as they were intended to be used. Otherwise, undefined behavior may result. (link)

上記の説明からわかるように、両方の割り当ては違法であり、一部のコンパイラによって生成された実行可能ファイルでは機能する可能性がありますが、他のコンパイラでは機能しない可能性があります。restrictの場合のように、実行しないことを選択できる特定の最適化を実行する機会を与えるだけなので、コンパイラ自体がエラーや警告を発することを期待しないでくださいvolatile

于 2010-09-27T04:05:44.400 に答える