Первые несколько ссылок. C99 Standard говорит это о restrict
в разделе 6.7.3:ключевое слово 'ограничить' - почему разрешено назначать из внешней ограниченной переменной внутреннюю ограниченную переменную?
Объект, который доступен через ограничение квалифицированного указателя имеет специальную ассоциацию с этим указателем. Эта ассоциация, определенная ниже в пункте 6.7.3.1, требует, чтобы все обращения к этому объекту прямо или косвенно использовали значение этого конкретного указателя. 117) Желаемого использования
restrict
классификатора (например, классregister
хранения) должен способствовать оптимизациям и удалением всех экземпляров классификатором из всех Preprocessing единицы перевода, составляющие соответствующих требований программы не меняет свое значения (т.е. , наблюдаемое поведение).
А потом (§6.7.3.1 «Формальное определение restrict
»):
Пусть
D
будет декларация обычного идентификатора, который обеспечивает средство от назначения объектаP
как restrict- квалифицированный указатель на типT
.Если
D
появляется внутри блока и не имеет классextern
хранения, пустьB
обозначают блок. ЕслиD
появляется в списке параметров объявлений определения функции, пустьB
обозначает связанный блок . В противном случае, пустьB
обозначает блок основной (или блок , любая функция вызывается при запуске программы в автономной среде ).В дальнейших, выражении указателя
E
называется основой на объектеP
, если (в некоторой точке последовательности в выполненииB
до оценокE
) модифицирующихP
, чтобы указать на копию объект массива , в который он ранее указывал, изменит значениеE
. 119) Примечание , что '' based '' определяется только для выражений с типами указателей.Во время каждого исполнения
B
, пустьL
быть любым именующим, который имеет&L
на основеP
. ЕслиL
используется для доступа к значению объектаX
, то его обозначает иX
также изменяется (любыми способами), то применяются следующие требования: :T
не должен быть const-квалифицированным. Каждое другое значение , используемое для доступа к значениюX
, также имеет свой адрес на основеP
. Каждый доступ, который изменяетX
, также должен изменитьP
, для целей настоящего подпункта.ЕслиP
присваивается значение выраженияE
в указатель, который основан на другом ограниченном указатель объектP2
, связанный с блокомB2
, то либо исполнениеB2
должно начаться до исполненияB
, или исполнениеB2
должны до назначения. Если эти требования не выполняются, то поведение не определено.
Как some have pointed out, это иллюстрирует правила (пример 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;
в первом примере выше)?
Пожалуйста, измените его так, чтобы он действительно компилировался. – gnasher729
Не единственное место, где вы можете объявить указатель как «ограничивать» в списке параметров функцией? – fuz
@FUZxxl Нет, стандарт не говорит об этом, и он отлично работает со всеми предупреждениями и обеспечивает строгое стандартное соответствие. – Norswap