Когда использовать ограничение и когда

У меня есть общее понимание restrict, но я надеюсь уточнить некоторые тонкости. У меня есть функция, которая считывает строку с нулевым завершением из одного буфера и выписывает версию с кодировкой URL в другом буфере. Функция имеет эту подпись (в настоящее время без restrict):

char const *StringUrlEncode(char const *unencoded, 
                            char *encoded,
                            char *encodedEnd);

unencoded - это исходная строка с нулевым завершением. Буфер назначения представлен encoded и encodedEnd, где encoded указывает на первый char в буфере, а encodedEnd указывает на первый char после буфера, то есть функция будет писать char до, но не включая местоположение, на которое указывает encodedEnd - это ваша базовая паратера итератора begin/end, если вы знакомы с соглашениями STL STL.

Если я добавлю restrict к этой функции, должен ли он применяться только к первым двум параметрам:

char const *StringUrlEncode(char const *restrict unencoded, 
                            char *restrict encoded,
                            char *encodedEnd);

или есть какое-то преимущество, которое я не понимаю, добавив его ко всем трем параметрам?

Я вижу, что создание входных и выходных буферов restrict помогает компилятору понять, что они не перекрываются. Но поскольку последний параметр encodedEnd используется только для обозначения конца выходного буфера, я думаю, что restrict не будет никакой помощью для компилятора здесь (хотя я предполагаю, что это не повредит, кроме добавления ненужного шума в объявление функции).

Ответ 1

Попробуйте статью Майка Актона здесь. Ограничение пугает из-за влияния производительности на неиспользование и последствий неправильного использования.

В вашем случае это звучит так, как будто вы можете безопасно применять ограничения для всех трех указателей, поскольку ни одна из них не имеет одинаковой области памяти. Однако от использования его на третьем указателе будет мало пользы от производительности.

Ответ 2

В этом конкретном случае не будет иметь значения, ограничивается ли encodedEnd; вы пообещали компилятору, что никто не псевдонимы unencoded и закодированы, поэтому чтения и записи не будут мешать друг другу.

Настоящая причина ограничения важна в этом случае: без него компилятор не может знать, что запись через закодированная не повлияет на чтение через unencoded. Например, если

encoded == unencoded+1

то каждая запись в закодированная будет влиять на каждое последующее чтение из unencoded, поэтому компилятор не может планировать загрузку до тех пор, пока запись не будет выполнена. ограничьте promises компилятор, что два указателя не влияют на одну и ту же память, поэтому он может планировать нагрузки достаточно далеко вперед, чтобы избежать конвейеров.

Ответ 3

Я думаю, ты прав, что это не повредит. Ваш указатель цикла (назовите его p) будет равен encodedEnd в конце цикла. Но ничто не должно быть доступно после цикла (из p или encodedEnd), поэтому это не должно быть проблемой. Я не думаю, что это тоже поможет, потому что ничего не написано и не прочитано из encodedEnd, поэтому ничего не нужно оптимизировать.

Но я согласен с тем, что первые два ограничения должны действительно помочь.