Алиасирование указателя массива - поведение undefined?
Вызывает ли следующий код поведение undefined (из-за нарушения псевдонимов или иначе)?
int foo(int (*a)[10], int (*b)[5])
{
(*a)[5]++;
return (*b)[0];
}
int x[10];
foo(&x, (int (*)[5])&x[5]);
Обратите внимание, что соответствующий код с использованием plain int *
, а не типа указателя на массив, будет совершенно легальным, потому что a
и b
будут указателями на один и тот же тип и, таким образом, будут иметь псевдоним друг друга.
Изменить: Интересное следствие, если это на самом деле является нарушением псевдонимов, заключается в том, что он кажется хакерским, но действительным способом получения семантики restrict
pre-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
Здесь вы не получаете доступа к объектам с помощью указателей различного типа: вы не манипулируете объектами массива, к которым указывают a
и b
, но объекты, на которые указывают (*a)+5
и (*b)+0
, а именно *((*a)+5)
и *((*b)+0)
. Так как это указатели на один и тот же тип, они могут быть похожими на один и тот же объект.
Неявное присвоение оператором ++
является допустимым назначением объекту, на который указывает (*b)+0
: ++
эквивалентно x = x + 1
(кроме того, x
оценивается только один раз) и для простого назначения =
стандарт говорит
Если значение, хранящееся в объекте, считывается с другого объекта который каким-либо образом перекрывает хранение первого объекта, затем наложение должно быть точным, и оба объекта должны иметь неквалифицированные версии совместимого типа; в противном случае поведение undefined.
Типы здесь точно такие же, и перекрытие является точным.