Ключевое слово restrict — спецификатор для указателей, введенный в стандарте C99. Оно сообщает компилятору, что указатель является единственным способом доступа к объекту памяти в рамках области видимости указателя. Это сильно помогает оптимизатору создавать более эффективный машинный код, особенно при работе с большими буферами.
Например:
void vector_add(int * restrict a, int * restrict b, int * restrict c, size_t n) { for (size_t i = 0; i < n; ++i) c[i] = a[i] + b[i]; }
Здесь предполагается, что массивы a, b и c не перекрываются. Нарушение этого требования приводит к неопределенному поведению и к сложноуловимым ошибкам.
Использование restrict рекомендуется только тогда, когда вы уверены, что никакие другие указатели или побочные пути не указывают на ту же память.
Может ли одно и то же значение памяти одновременно быть видимым через два restrict-указателя?
Ответ:
Нет, это приведет к undefined behavior. Нет гарантии, что компилятор учтет изменения, внесенные через второй указатель. Пример — критически неверный код:
void f(int * restrict x, int * restrict y) { x[0] = 1; y[0] = 2; } int main() { int v; f(&v, &v); // Нарушение условия restrict }
История
В финансовом расчётном ядре функции оптимизировали массивы с добавлением restrict, но не учли, что массивы могут перекрываться по требованию части бизнес-логики. Это привело к неверному расчету баланса при некорректном использовании.
История
Метод batch-перемножения матриц ускорился после применения restrict, но в одной из итераций массив результата пересекался с одним из входных массивов — ответ становился непредсказуемым, баг ловился только нагрузочным тестированием.
История
В одной из функций image processing два указателя на куски одного и того же буфера были случайно объявлены с restrict. После обновления компилятора и его оптимизатора результат обработки изображений резко стал искаженным — причина: компилятор стал активно реиспользовать кэш и игнорировал модификации.