restrict — ключове слово в мові програмування C, введене стандартом C99 і використовуване в оголошеннях вказівників.char * restrict p1; int ** restrict p2; float * restrict p3, * restrict p4;Ключове слово restrict дозволяє програмісту повідомити компілятору, що оголошуваний вказівник адресує ділянку пам'яті, на яку не посилається ніякий інший вказівник. Гарантію того, що на ділянку пам'яті не будуть посилатися інші вказівники, дає програміст. При цьому оптимізувальний компілятор може генерувати ефективніший код (приклад див. нижче).

Використання ключового слова restrict при оголошенні інших об'єктів (не вказівників) стандартом не визначено.

При використанні ключового слова restrict програма, написана на «розумному» C, може зрівнятися за швидкістю з програмою, написаною на «дурному» Fortran - Без ключового слова restrict компілятор вважає, що вказівники можуть вказувати на той самий блок пам'яті, і генерує не оптимальний код. Це одна з причин того, що мова Fortran все ще використовується для числових розрахунків (дозволяє писати швидкий код простіше). Теоретично, введення restrict у C99 має вирішити цю проблему..

У мові C++ немає ключового слова restrict (не описано в стандарті), але розробники різних компіляторів C++ додали аналогічні за призначенням ключові слова, наприклад:

__restrict і __restrict__ у GNU Compiler Collectiongnu.org Restricting pointer aliasing . Документація gcc.; __restrict і __declspec(restrict) у Visual C++; __restrict__ у Clang.

Приклад оптимізації Компілятор може створювати менше коду, якщо знає, що тільки один вказівник адресує один блок пам'яті. Розглянемо приклад. Визначено таку функцію:void updatePtrs( size_t* ptrA, size_t* ptrB, size_t* val ) { *ptrA += *val; *ptrB += *val; }Вказівники ptrA, ptrB і val можуть посилатися на один і той самий блок пам'яті.

Для цієї функції компілятор буде генерувати приблизно такий код:; прочитати значення з пам'яті за вказівником val load R1 ← *val

; прочитати значення з пам'яті за вказівником ptrA load R2 ← *ptrA

; виконати додавання add R2 += R1

; записати результат у пам'ять за вказівником ptrA set R2 → *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Зауважте, що код став коротшим через те, що значення 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; // невизначена поведінка

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  — про причини введення.

Примітки

Література