Является ли это недопустимым использованием указателей restrict?
предположим, что у меня большой массив, в который я вычисляю индекс и передаю второй функции. В качестве простого примера, что-то вроде:
void foo(float* array, float c, unsigned int n)
{
for (unsigned int i = 0; i < n; ++i)
array[i] *= c;
}
void bar(float* restrict array, float* restrict array2, unsigned int m, unsigned int n)
{
for (unsigned int i = 0; i < m; ++i)
foo(&array[i * n], array2[i], n);
}
это нарушение правил ограничения в bar(), где вы передаете адрес части массива foo (), даже если вы никогда не используете псевдоним для части массива в bar ()?
2 ответов
(все цитаты относятся к N1256, который является C99 плюс технические исправления (TC3).)
формальное определение restrict приведен в п. 6.7.3.1. Я цитирую самый важный подпункт ниже. P - это restrict - квалифицированный указатель на тип T чья область действия является блоком B. Выражение указателя E считается на основе P если это зависит от значения P сам, а не значение, которое P очки к.
во время каждого исполнения
B, пустьLбыть любой lvalue, который имеет&Lна основе P. IfLиспользуется для доступа к значению объектаXчто он обозначает, иXтакже изменено (любыми средствами), тогда применяются следующие требования:
Tне будет const-квалифицировано.- каждый другой lvalue используется для доступа к значению
Xтакже имеет свой адрес, основанные наP.- каждый доступ, который изменяет
Xсчитается также изменитьPдля целей настоящего подпункта.- если
Pприсваивается значение выражения указательEэто основано на другом ограниченном объекте указателяP2, связанный с блокомB2, тогда как исполнениеB2должно начаться до исполненияB, илиB2заканчивается до назначения.если эти требования не выполнены, то поведение не определено.
давайте посмотрим, что правила должны сказать о доступе к частям bar ' s array на foo. Начнем с array, указатель с ограничениями, объявленный в списке параметров bar. Для ясности я буду Альфа-конвертировать параметры foo:
void foo(float* b, float c, unsigned int n) { /*modify b[i]*/ }
хранилище, на которое указывает array также изменяется через b. Это хорошо со вторым пунктом пули как &array[i*n] эквивалентно array+(i*n) (см. п. 6.5.3.2).
если b был ограничен-квалифицированный, тогда мы должны были бы проверить четвертом пункте с P←b, B←foo, P2←array, B2←bar. С B вложен внутрь B2 (функции ведут себя так, как будто встроены здесь, см. §6.7.3.1.11), первое условие выполнено. Существует также один экземпляр третьего маркера (The доступ к b[i] на foo), что не является проблемой.
b не ограничивать квалификацию. Согласно §6.3.2.3.2, " для любого классификатора q указатель на не-q-квалифицированный тип может быть преобразован в указатель на q-квалифицированная версия типа; значения, хранящиеся в исходном и преобразованном указателях, должны сравниваться равными". Поэтому преобразование из array+(i*n) to b хорошо определен и имеет очевидное значит, поведение программы определено. Более того, поскольку b не restrict-квалифицированный, ему не нужно повиноваться никакому условию линейности. Например, следующее foo является законным в сочетании с bar:
void qux(float *v, float *w) {
v[0] += w[0];
}
void foo(float* b, float c, unsigned int n)
{
qux(b,b);
}
добавил: чтобы решить вашу конкретную проблему "в bar (), где вы передаете адрес части массива foo ()", это не проблема: restrict применяется к указателю, а не массиву, и вы можете выполнять арифметику на нем (пункт 2).
нет, restrict означает, что массив не может ничего псевдонима, поэтому вы можете передавать материал в бар, не нарушая правил