2011-08-15 13 views
13

次のコードは、(エイリアス違反などの理由で)未定義の動作を呼び出しますか?配列ポインタのエイリアシング - 未定義の動作?

int foo(int (*a)[10], int (*b)[5]) 
{ 
    (*a)[5]++; 
    return (*b)[0]; 
} 

int x[10]; 
foo(&x, (int (*)[5])&x[5]); 

abが同じタイプへのポインタであり、従って、エイリアス互いにせてしまうためではなくポインタ・ツー・アレイタイプより普通int *を使用して、対応するコードは、完全に合法であろうことに留意されたいです。

編集:興味深い結果、これは実際にはエイリアシング違反であれば、restrictセマンティクス事前C99を取得するためのハックが、有効な方法であると思われることです。以下のように:あなたは、各アドレスに実際の配列にアクセスするために必要なおそらく場合

void some_func(int *aa, int *bb) 
{ 
    int (*a)[1] = (void *)aa; 
    int (*b)[2] = (void *)bb; 
    /* Now **a and **b can be assumed by the compiler not to alias */ 
} 

、あなたは、異なるサイズとしてSIZE_MAX-1およびSIZE_MAX-2などを使用することができます。

+1

これらは同じタイプのポインタです。エイリアスではないとみなすことはできません。 –

答えて

4

あなたが、ここでは異なるタイプのポインタを介したオブジェクトにアクセスしていない:あなたは、配列オブジェクトを操作していないためにどのa自体が、オブジェクトが(*a)+5(*b)+0、すなわち*((*a)+5)*((*b)+0)によって指さbポイント。これらは同じ型へのポインタなので、同じオブジェクトに別名を付けることができます。

++オペレータによる暗黙の割り当ては(*b)+0によって指されたオブジェクトへの有効な割り当てです:++は(xは一度だけ評価されているほか)x = x + 1と同じで、単純な代入=のための標準は

を語りますあるオブジェクトに格納されている値が他のオブジェクトから読み取られた場合、最初のオブジェクトの格納に重複するものがある場合は、 の重複が厳密になり、2つのオブジェクトには修飾された互換性のあるt ype;そうでない場合は、動作は となります。

ここでのタイプはまったく同じで、オーバーラップは正確です。

+0

+1非常に面白いです。しかし、私はまだこのポインタのセマンティクスのことを嫌いです... –

+0

このロジックでは、 'int [5] [5]'とオーバーレイされた 'int [25] 'にもアクセスできません...? –

+0

@R ..はい、私はそれが有効だろうと思います。配列は何とか灰色のゾーンにあります。 'struct'の場合、フィールド' toto.x 'にアクセスすると全体としてオブジェクトにアクセスし、 'A [24]'と 'B [4] [4]'はポインタ算術演算で定義されているので、配列全体として。 –

関連する問題