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

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

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

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

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

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

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

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

3 ответа

Решение

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

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

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

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

encoded == unencoded+1

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

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

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

Другие вопросы по тегам