2014-09-19 5 views
3

целая точка of restrict - обещать доступ через один указатель, а не другой. Тем не менее, есть примеры, когда перекрывающиеся адреса памяти не будут подразумевать сглаживание. Например:Гранулярность ограничителя для наложения указателей, типов

int* arr_ptr0 = &arr[0]; 
int* arr_ptr1 = &arr[1]; 
for (int i=0;i<10;++i) { 
    *arr_ptr0 = *arr_ptr1; 
    arr_ptr0 += 2; 
    arr_ptr1 += 2; 
} 

Дело в том, эти указатели на самом деле сделать точку перекрытия памяти! В данном конкретном примере такие направляющие, как this, например, например:

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

Мой вопрос: Какая зернистость является «элементами»?

Например, предположим, что у меня есть массив типа struct Foo. Должен ли я действительно гарантировать, что я не получаю доступ к одному и тому же диапазону элементов (Foo s), даже если частей Я имею доступ непересекающимися? Вот простой, скалярный пример:

struct Foo { int i; float f; }; 
void f(struct Foo*restrict foo0, struct Foo*restrict foo1) { 
    foo0->i = 6; 
    foo1->f = 19.0f; 
} 
void g(struct Foo* foo) { 
    f(foo,foo); /* problem? */ 
} 

Вы можете столкнуться с подобными проблемами с указателями различных типов (например, char против int), но, возможно, структура выше примером является более ясным.

+0

AFAIUI, да, вам действительно нужно убедиться, что вы не имеете доступа к той же структуре, независимо от какой части структуры, к которой вы обращаетесь, через два разных указателя. Это даже не вопрос «того же времени»; это «тот же вызов функции». Итак, если вы обращаетесь к 'ptr1 [a] .. ptr1 [b]' (a

+0

@JonathanLeffler: Это не «тот же вызов функции», а время жизни выполнения конкретного блока, связанное с временем жизни указателя с ограничением. –

ответ

-1

Ключевое слово restrict строго советует компилятору, что приложение не будет изменять одни и те же адреса с помощью другого указателя, не полученного из него, в пределах допустимого класса.

Ничего фактически не ограничивает применение от этого. Тем не менее, можно с уверенностью предполагать изменение адреса, доступ к которому осуществляется с помощью квалифицированного указателя restrict через нечто отличное от этого restrict квалифицированный указатель приведет к undefined поведение (остерегайтесь драконов).

1

Соответствующий текст стандарта является 6.7.3.1 Формальное определение ограничивает:

1 Пусть D будет декларация обычного идентификатора, который обеспечивает средство назначения объект P в качестве restrict- квалифицированный указатель на тип T.

2 Если D появляется внутри блока и не имеет внешнего класса хранения, пусть B обозначает блок. Если D появляется в списке объявлений параметров определения функции, пусть B обозначает соответствующий блок. В противном случае пусть B обозначает блок main (или блок любой функции вызывается при запуске программы в автономной среде).

3 В дальнейшем выражение указателя E называется основанием на объекте P, если (в некоторой точке последовательности при выполнении B до оценки E), изменяя P, указывать на копию объекта массива в который он ранее указывал, изменил бы значение E.137). Обратите внимание, что '' based '' определяется только для выражений с типами указателей.

4 Во время каждого исполнения B пусть L - любое lvalue, которое имеет & L на основании P.Если L используется для доступа к значению объекта X, которое он обозначает, а X также изменяется (любыми способами), тогда применяются следующие требования: T не должен быть const-квалифицированным. Каждая другая lvalue, используемая для доступа к значению X, также имеет свой адрес, основанный на P. Каждый доступ, который модифицирует X, должен также рассматриваться для изменения P для целей данного подпункта. Если P присвоено значение выражения E указателя, которое основано на другом объекте P2 с ограниченным указателем, связанным с блоком B2, то либо выполнение B2 должно начинаться до исполнения B, либо выполнение B2 должно заканчиваться до назначение. Если эти требования не выполняются, то поведение не определено.

-Здесь исполнение B означает ту часть выполнения программы, которая соответствовала бы времени жизни объекта с скалярным типом и автоматической продолжительностью хранения, связанный с Б.

Вашего первым примером (чередующийся массив) отлично работает по моему чтению стандарта.

Второй пример с структуры менее ясна, и зависит от того, является ли использование оператора -> (ваш написал ., но имел в виду ->) с foo0 (или foo1) означает, что *foo0 (или foo1) «, используемый для доступа значение объекта, который он обозначает ". Это мне не ясно, так как структура не используется в качестве значения; только его члены.

+0

Вы правы; Я имел в виду '->'; изменилось. – imallett

+0

, если вы не рассматриваете доступ к членам как доступ к совокупности, некоторые части стандарта C (например, 'ограничивать", как мы видели, а также '_Atomic') становятся очень ... допустим,« интересными »; в случае изменения доступа, возможно, ясно, что доступ к члену подразумевает доступ к совокупности: если значение члена изменяется, то также изменяется значение совокупности, подразумевая, что к нему был получен доступ по определению; предполагая, что цель стандарта заключалась в том, чтобы не сбивать программистов на C совершенно безумным, то же самое должно иметь место для немодифицирующего доступа, но жюри на этом все еще отсутствует;) – Christoph

+0

hm .. scratch '_Atomic' из моего аргумента, в любом случае не допускается доступ к элементам атомных структур; аргумент верен для 'volatile'; также обратите внимание, что противоположный случай (доступ к агрегату подразумевает доступ к члену) получает явное упоминание в эффективных правилах набора текста (но, конечно, не имеет значения) – Christoph