Рассмотрим эти две функции:
void foo(char * __restrict localPtr)
{
// some work with localPtr
}
void bar(char * __restrict ptr)
{
// some work with ptr
foo(_ptr);
// some other work with ptr
}
Как ptr
был объявлен __restrict
в bar
, звонит foo()
опасно? Под опасным я имею в виду, что зона памяти, указанная localPtr
перекрывается ptr
один. Каковы рекомендации по этому поводу?
restrict
квалификатор означает, что единственный способ для вызываемой функции получить доступ к памяти, переданной как localPtr
в foo
через этот указатель; в этой памяти нет псевдонимов. Это может позволить оптимизатору создавать лучший код, потому что ему не нужно беспокоиться о другом указателе, также изменяющем данные.
В этом контексте и в большинстве других restrict
Квалификатор возлагает на вас ответственность, программист, выполняющий вызовы, чтобы убедиться, что вы соблюдаете требование «без псевдонимов».
Там нет видимой опасности от кода выше.
Обратите внимание, что чаще всего у вас есть несколько указателей в списке аргументов, когда restrict
используется. Из стандарта C сравните:
void *memcpy(void *restrict s1, const void *restrict s2, size_t n);
void *memmove(void *s1, const void *s2, size_t n);
Первый (memcpy()
) говорит, что куски памяти [s1 .. s1+n-1]
а также [s2 .. s2+n-1]
не должен перекрываться; вы получите неопределенное поведение, если они действительно перекрываются. Второй (memmove()
) не навязывает это требование.
Но это не призыв к
foo()
создание другого указателя, который изменяет данные?
Да, нет, вроде … но в основном нет.
Указатель в foo()
безусловно передается bar()
, но пока bar()
работает, единственный путь bar()
можно получить в память через указатель, он был передан. таким образом bar()
может быть скомпилирован при условии, что у него нет псевдонима для памяти, с которой он работает.
Когда компилятор обрабатывает foo()
, он знает (гарантирует), что после аргументов bar()
оцениваются и перед вызовом функции, и другим, когда функция возвращается. Он знает, что данные могли быть изменены bar()
так как это не было передано const char *
, Поэтому он сгенерирует код для учета этих возможностей. Тем не менее, компилятор также знает, что единственный способ, которым foo()
может получить доступ к памяти, адресуемой localPtr
через localPtr
(вот что restrict
говорит), и это может продолжаться на основе этого предположения.
Итак, есть вторая копия указателя, а bar()
называется, но это не является нарушением правил restrict
в любом случае.
Других решений пока нет …