(все ссылки относятся к N1256 , что является C99 плюс технические исправления (TC3).)
Формальное определение restrict
дано в §6.7.3.1.Я цитирую самый важный подпункт ниже.P
- это restrict
-качественный указатель на тип T
, область действия которого - блок B
.Выражение указателя E
называется на основе P
, если оно зависит от самого значения P
, а не от значения, на которое указывает P
.
Во время каждого выполнения B
, пусть L
будет любым lvalue, который имеет &L
на основе P. Если L
используется для доступа к значению объекта X
, который он обозначает, и X
также изменяется (любым способом), тогда применяются следующие требования:
T
не должно быть константным. - Любое другое значение lvalue, используемое для доступа к значению
X
также должен иметь свой адрес, основанный на P
. - Каждый доступ, который изменяет
X
, также считается модифицированным P
, для целей этого подпункта. - Если
P
присваивается значение выражения указателя E
, основанное на другом ограниченном объекте указателя P2
, связанном с блоком B2
, тогда либо выполнение B2
должно начаться до выполнения B
или исполнение B2
должно закончиться доназначение.
Если эти требования не выполнены, то поведение не определено.
Давайте посмотрим, что правила должны сказать о доступе к деталямbar
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 , может быть преобразован в указатель на q -качественная версия типа;значения, сохраненные в исходном и преобразованном указателях, должны сравниваться одинаково ».Поэтому преобразование из array+(i*n)
в 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);
}
ADDED : для решения вашей конкретной проблемы «в bar (), где вы проходитеадрес части массива для foo () », это не проблема: restrict
применяется к указателю, а не к массиву, и вы можете выполнить арифметику с ним (пункт 2).