16

次のコードは未定義の動作を引き起こしますか (エイリアシング違反またはその他による)?

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

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

と は同じ型へのポインターになり、相互にエイリアスを許可するため、int *配列へのポインター型ではなくプレーンを使用する対応するコードは完全に合法であることに注意してください。ab

編集:これが実際にエイリアシング違反である場合、興味深い結果は、restrictC99より前のセマンティクスを取得するためのハックだが有効な方法であるように見えることです。次のように:

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 などを使用できます。

4

1 に答える 1

6

ここでは、異なる型のポインターを介してオブジェクトにアクセスしていません。 と が指している配列オブジェクトを操作しているのではなく、abが指しているオブジェクト、つまり(*a)+5とを操作しています。これらは同じ型へのポインタであるため、同じオブジェクトへのエイリアスである可能性があります。(*b)+0*((*a)+5)*((*b)+0)

++演算子による暗黙の代入は、 が指すオブジェクトへの有効な代入です(*b)+0:は( 1 回だけ評価されること++を除いて) と同等であり、単純な代入の場合、標準は次のように述べています。x = x + 1x=

オブジェクトに格納されている値が、最初のオブジェクトのストレージとオーバーラップする別のオブジェクトから読み取られる場合、オーバーラップは正確であり、2 つのオブジェクトは互換性のある型の修飾バージョンまたは非修飾バージョンを持つ必要があります。それ以外の場合、動作は未定義です。

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

于 2011-08-15T09:09:45.277 に答える