restrict — ключевое слово в языке программирования C, введённое стандартом C99 и используемое в объявлениях указателей. char * restrict p1; int ** restrict p2; float * restrict p3, * restrict p4; Ключевое слово restrict позволяет программисту сообщить компилятору, что объявляемый указатель адресует область памяти, на которую не ссылается никакой другой указатель. Гарантию того, что на участок памяти не будут ссылаться более одного указателя, даёт программист. При этом оптимизирующий компилятор может генерировать более эффективный код (пример см. ниже).
Использование ключевого слова restrict при объявлении других объектов (не указателей) не определено стандартом.
При использовании ключевого слова restrict «умный» Си нагоняет «глупый» Фортран (тот держит матрицы в транспонированном виде 00, 10, 01, 11, это полезно для кэша на операциях линейной алгебры).
В языке C++ нет ключевого слова restrict (не описано в стандарте), но разработчики разных компиляторов C++ добавили аналогичные по назначению ключевые слова, например: __restrict и __restrict__ у GNU Compiler Collectiongnu.org Restricting pointer aliasing . Документация gcc.; __restrict и __declspec(restrict) у Visual C++; __restrict__ у Clang.
Пример оптимизации Запись по указателю всегда вызывает вопрос: какие данные, вероятно, изменились и нужно снова загружать из памяти в регистры, а какие — остались нетронутыми? Так что компилятор может генерировать более оптимальный машинный код, если знает, что только один указатель адресует определённый блок памяти — начиная от исключения таких загрузок и заканчивая векторными операциями процессора, которые годятся для memcpy и опасны для memmove.
Это можно проиллюстрировать функцией:
void updatePtrs( size_t* ptrA, size_t* ptrB, size_t* val ) { *ptrA += *val; *ptrB += *val; }
Компилятор предполагает, что указатели ptrA, ptrB и val могут ссылаться на один и тот же блок памяти.
Для этой функции компилятор будет генерировать примерно следующий код:
load R1 ← *val ; прочитать значение из памяти по указателю val
load R2 ← *ptrA ; прочитать значение из памяти по указателю ptrA add R2 += R1 ; выполнить сложение set R2 → *ptrA ; записать результат в память по указателю ptrA
; аналогично для ptrB load R1 ← *val ; чтение по val второй раз
load R2 ← *ptrB add R2 += R1 set R2 → *ptrB
В данном примере значение по указателю val считывается из памяти дважды. Это происходит из-за того, что указатель ptrA может ссылаться на тот же блок памяти, что и val, то есть значение val может измениться при записи значения по указателю ptrA.
При использовании ключевого слова restrict определение функции будет следующим:
void updatePtrs( size_t* restrict ptrA, size_t* restrict ptrB, size_t* restrict val ) { *ptrA += *val; *ptrB += *val; }
Ключевое слово restrict сообщает компилятору, что указатели ptrA, ptrB и val никогда не адресуют один и тот же блок памяти. Это гарантируется программистом.
В этом случае компилятор будет генерировать примерно следующий код:
load R1 ← *val
load R2 ← *ptrA add R2 += R1 set R2 → *ptrA
; load R1 ← *val ; отсутствует
load R2 ← *ptrB add R2 += R1 set R2 → *ptrB
В результате применения ключевого слова restrict код стал короче благодаря тому, что значение val читается из памяти только один раз.
Примеры неопределённого поведения Указатель с квалификатором типа restrict на указатель с квалификатором типа restrict может быть определён только во вложенном блоке. Пример:
struct T { int i; }; struct T var_1;
int main() { struct T* restrict var_2 = &var_1; int* restrict var_3 = &var_2->i; // undefined behavior
int* restrict var_4 = &var_2->i; // допустимо
return 0; } Определение указателя var_3 — неопределённое поведение, так как var_3 находится в одном блоке с var_2. Определение var_4 находится во вложенном блоке и допустимо.
__restrict для методов в C++
Ключевое слово __restrict для метода структуры или класса C++ обозначает, что указатель имеет тип «». Пример: struct T { void method () __restrict {}
Литература
См. также
Demystifying the restrict keyword. Объяснение и примеры использования.
Restricted pointers in C. Причины введения.
Примечания
Категория:Си (язык программирования)