Для справки, вот довольно запутанное определение квалификатора restrict
(из C99 6.7.3.1 «Формальное определение ограничения»):
Пусть D будет объявлением обычного идентификатора, который предоставляет средства для обозначения объекта P как указателя с ограничением на тип T.
Если D появляется внутри блока и не имеет внешнего класса хранения, пусть B обозначает блок. Если D появляется в списке объявлений параметров определения функции, пусть B обозначает соответствующий блок. В противном случае пусть B обозначает блок main (или блок любой функции, вызываемой при запуске программы в автономной среде).
В дальнейшем говорят, что выражение указателя E основано на объекте P, если (в какой-то точке последовательности выполнения B перед вычислением E) P модифицируется так, чтобы он указывал на копию объекта массива, на который он ранее указывал. изменит значение E. Обратите внимание, что "основанный" определен только для выражений с типами указателей.
Во время каждого выполнения B пусть L будет любым lvalue, которое имеет &L на основе P. Если L используется для доступа к значению объекта X, которое он обозначает, и X также изменяется (любыми способами), то применяются следующие требования. : T не должен быть const-квалифицированным. Каждое другое lvalue, используемое для доступа к значению X, также должно иметь свой адрес, основанный на P. Каждый доступ, который изменяет X, также должен рассматриваться как модифицирующий P для целей этого подпункта. Если P присваивается значение выражения указателя E, которое основано на другом ограниченном объекте указателя P2, связанном с блоком B2, то либо выполнение B2 должно начаться до выполнения B, либо выполнение B2 должно закончиться до выполнения B2. назначение. Если эти требования не выполняются, то поведение не определено.
Здесь выполнение B означает ту часть выполнения программы, которая соответствует времени жизни объекта скалярного типа и продолжительности автоматического хранения, связанного с B.
Мое прочтение вышеизложенного означает, что в вашем первом вопросе a
не может быть назначено b
даже внутри «дочернего» блока - результат не определен. Такое присвоение можно было бы сделать, если бы b
было объявлено в этом «подблоке», но поскольку b
объявлено в той же области, что и a
, присвоение не может быть выполнено.
Для вопроса 2 назначения между c
и d
также приводят к неопределенному поведению (в обоих случаях).
Соответствующий бит из стандарта (для обоих вопросов):
Если P присваивается значение выражения указателя E, которое основано на другом ограниченном объекте указателя P2, связанном с блоком B2, то либо выполнение B2 должно начаться до выполнения B, либо выполнение B2 должно закончиться до выполнения B2. назначение.
Поскольку ограниченные указатели связаны с одним и тем же блоком, блок B2 не может начаться до выполнения блока B или завершиться блоком B2 до выполнения присваивания (поскольку блоки B и B2 — это один и тот же блок).
Стандарт дает пример, который делает это довольно ясным (я думаю, что ясность 4 коротких абзацев определения restrict
соответствует правилам разрешения имен C++):
ПРИМЕР 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
}
}
person
Michael Burr
schedule
27.09.2010