2015-03-26 12 views
15

Первые несколько ссылок. 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; в первом примере выше)?

+0

Пожалуйста, измените его так, чтобы он действительно компилировался. – gnasher729

+0

Не единственное место, где вы можете объявить указатель как «ограничивать» в списке параметров функцией? – fuz

+0

@FUZxxl Нет, стандарт не говорит об этом, и он отлично работает со всеми предупреждениями и обеспечивает строгое стандартное соответствие. – Norswap

ответ

-4

Ничто из этого не является неопределенным поведением. Вы можете назначить между указателями ограничений все, что вам нравится. Неопределенное поведение может возникать, если вы назначаете объекты, на которые указали, указав указатели указателей неправильно.

И в вашем втором примере указатель y является производным от x, поэтому сначала назначить * x, а затем на ту же переменную, что и * y, также отлично.

Вместо того, чтобы читать легализацию, вы действительно думали о том, что «ограничивать» должно быть достигнуто?

+1

Ну, стандарт противоречит вам, без сомнения. И да, я подумал об этом; и я задаю вопрос, так как мой интуитивный понять точно не мешает тому, что говорит стандарт. Я делаю предположение, что стандарт не был написан полными идиотами, и поэтому должна быть причина его причуд. Кроме того, это комментарий; не ответ. – Norswap

+1

Не могли бы вы указать, где я заблуждаюсь, вместо того, чтобы выходить из гоминимов? Также учтите, что это не только мое чтение, но и другие пользователи stackoverflow по вопросу, который я связал, и [здесь] (http://www.lysator.liu.se/c/restrict.html), и никто противоречить (конечно, это ничего не доказывает). – Norswap

1

Я думаю, что правила призваны удовлетворять двум целям:

  1. Разрешить создание временного указателя аналогично тому, что, естественно, будет создан, когда аргумент передается вызов функции, не требуя, чтобы код, используя указатель перемещается в физически раздельную функцию.

  2. Убедитесь, что график, показывающий вывод указателя, не содержит циклов (это означает, что если указатель x получен из y или что-либо, прямо или косвенно полученное из y, y не может быть выведено из x или ничего, что непосредственно или косвенно полученной из x). Хотя правила могут быть более жесткими, чем это было бы абсолютно необходимо для достижения № 2, почти все полезные случаи, которые удовлетворяли бы этому второму требованию, также удовлетворяли бы правилам, как написано, а компиляторам было бы трудно получить большую выгоду от restrict в случаях, когда дон «т.

restrict Классификатор далек от совершенства, но это все-таки лучше, чем большинство альтернатив.