restrict
restrict — ключевое слово в языке программирования C, введённое стандартом C99 и используемое в объявлениях указателей.
char * restrict p1;
int ** restrict p2;
float * restrict p3, * restrict p4;
Ключевое слово restrict
позволяет программисту сообщить компилятору, что объявляемый указатель адресует область памяти, на которую не ссылается никакой другой указатель. Гарантию того, что на участок памяти не будут ссылаться более одного указателя, даёт программист. При этом оптимизирующий компилятор может генерировать более эффективный код (пример см. ниже).
Использование ключевого слова restrict
при объявлении других объектов (не указателей) не определено стандартом.
При использовании ключевого слова restrict
программа, написанная на «умном» C, может сравниться по скорости с программой, написанной на «глупом» Fortran[1].
В языке C++ нет ключевого слова restrict
(не описано в стандарте), но разработчики разных компиляторов C++ добавили аналогичные по назначению ключевые слова, например:
__restrict
и__restrict__
у GNU Compiler Collection[2];__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
могут ссылаться на один и тот же блок памяти.
Для этой функции компилятор будет генерировать примерно следующий код:
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++ обозначает, что указатель this
имеет тип «T * __restrict const
». Пример:
struct T {
void method () __restrict {}
};
Литература
[править | править код]- Черновик стандарта ISO/IEC 9899:TC2. Язык программирования C : журнал. — ISO, 2005. — 6 мая. — С. 108—112.
См. также
[править | править код]- Demystifying the restrict keyword (англ.). Объяснение и примеры использования.
- Walls, Douglas Использование ключевого слова restrict в языке C (англ.) . Oracle™. Дата обращения: 21 ноября 2012.
- Restricted pointers in C (англ.). Причины введения.
Примечания
[править | править код]- ↑ Ulrich Drepper. Память. Часть 5 . Что каждый программист должен знать о памяти. Электронный журнал lwn.net (23 октября 2007). — Без ключевого слова
restrict
компилятор считает, что указатели могут указывать на один и тот же блок памяти, и генерирует не оптимальный код. Это одна из причин, по которым язык Fortran всё ещё используется для численных расчётов (позволяет писать быстрый код проще). Теоретически, введениеrestrict
в C99 должно решить эту проблему. Дата обращения: 5 декабря 2014. Архивировано 30 марта 2015 года. - ↑ gnu.org Restricting pointer aliasing Архивная копия от 6 августа 2016 на Wayback Machine (англ.). Документация gcc.