(Все цитаты относятся к N1256, который C99 плюс технические исправления (ТС3).)
Формальное определение restrict
приведено в разделе 6.7.3.1. Я цитирую самый важный подпункт ниже. P
является restrict
-qualified указатель для типа T
, объем которого является блоком B
. Выражение указателя E
называется на основеP
, если оно зависит от значения P
, а не от значения, которое P
указывает на.
Во время каждого выполнения B
, пусть L
быть любым именующим, который имеет &L
основанные на P. Если L
используется для доступа к значению объекта 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), выполняется первое условие. Существует также одна инициализация третьей точки маркировки (доступ к b[i]
в foo
), что не является проблемой.
Однако b
не имеет ограничений. Согласно §6.3.2.3.2, «для любого классификатора q указатель на не-q -qualified тип может быть преобразован в указатель на q -qualified версия типа; значения, хранящиеся в исходных и преобразованных указателях, сравниваются равными ». Поэтому преобразование с array+(i*n)
в b
четко определено и имеет очевидное значение, поэтому определяется поведение программы. Кроме того, поскольку b
не является restrict
-qualified, ему не нужно подчиняться никакому условию линейности. Например, следующий foo
является законным в сочетании с bar
:
void qux(float *v, float *w) {
v[0] += w[0];
}
void foo(float* b, float c, unsigned int n)
{
qux(b,b);
}
ДОБАВЛЕНО: Для того, чтобы решить вашу конкретную озабоченность «в строке(), где вы передаете адрес части массива Foo () ", Это не проблема: restrict
применяется к указателю, а не к массиву, и вы можете выполнить арифметику на нем (точка 2).
Я не могу сказать, говоришь ли вы, что это правильно или неправильно, но реквизит для развертывания стандарта полностью. –
@Matt: Код верный (отчасти потому, что правила ограничения здесь не очень много, а отчасти потому, что вы можете конвертировать ограничитель в подкласс, ограниченный 'foo'). – Gilles