Сначала несколько ссылок. C99 Standard говорит об restrict
в разделе 6.7.3:
Объект, к которому осуществляется доступ с помощью указателя с ограничением, имеет специальная ассоциация с этим указателем. Эта ассоциация, определенная в 6.7.3.1 ниже, требует, чтобы все обращения к этому объекту прямо или косвенно использовали значение этого конкретного указателя. 117)использование квалификатора
restrict
(например, класс храненияregister
) - это содействовать оптимизации и удалять все экземпляры квалификатора из все единицы перевода для предварительной обработки, составляющие соответствующую программу не меняет его значения (т.е. наблюдаемого поведения).
И затем (§6.7.3.1 "Формальное определение restrict
" ):
Пусть
D
является объявлением обычного идентификатора, который предоставляет средства о назначении объектаP
в качестве указателя с ограничениями типаT
.Если
D
появляется внутри блока и не имеет класса храненияextern
, пустьB
обозначает блок. Если в списке параметров появляетсяD
объявления определения функции, пустьB
обозначает ассоциированный блок. В противном случае пустьB
обозначает блок main (или блок любая функция вызывается при запуске программы в автономном режиме среда).В дальнейшем выражение указателя
E
называется основанным на объектеP
, если (в некоторой точке последовательности при выполненииB
до оценкаE
), изменяющаяP
, чтобы указать на копию объекта массива в который он ранее указал, изменит значениеE
. 119) Примечание. что '' based '' определяется только для выражений с типами указателей.При каждом выполнении
B
пустьL
будет любое значение l, которое имеет&L
на основеP
. ЕслиL
используется для доступа к значению объектаX
, чтобы оно иX
также изменяется (любыми способами), то следующие применяются требования:T
не должен быть const-квалифицированным. Все остальные значения используемый для доступа к значениюX
, также должен иметь свой адрес на основеP
. Каждый доступ, который изменяетX
, должен также быть измененP
, для цели этого подпункта. ЕслиP
присвоено значение a выражение указателяE
, которое основано на другом ограниченном указателе объектP2
, связанный с блокомB2
, то либо выполнениеB2
начинаются до выполненияB
, или выполнениеB2
должно до назначения. Если эти требования не выполняются, то поведение undefined.
Поскольку некоторые указали, это иллюстрирует правила (пример 4 из стандарта):
{
int * restrict p1;
int * restrict q1;
p1 = q1; // undefined behavior
{
int * restrict p2 = p1; // valid
int * restrict q2 = q1; // valid
p1 = q2; // undefined behavior
p2 = q2; // undefined behavior
}
}
Теперь мой первый вопрос заключается в следующем: почему это нормально назначать из внешнего ограниченного указателя на внутренний?
Я понимаю, что ничто не запрещает это, у которого есть ясное наложение:
int * restricted x = /* ... */ ;
{
int * restricted y = x;
*x = 3;
printf("%d\n", *y); // 3
*y = 4;
printf("%d\n", *x); // 4
}
Конечно, набор псевдонимов ограничен двумя указателями.
Следовательно, мой второй вопрос: какая разница назначается от внешнего к внутреннему (разрешенному), но не от внутреннего к внешнему (запрещена, например, p1 = q1;
в первом примере выше)?