Что является хорошим примером использования переменной регистра в C?
Я читаю K&R и пришел к небольшому разделу о переменных реестра, и мне было интересно, есть ли у людей здесь некоторые хорошие примеры этого на практике.
Из раздела 4.7 в K&R:
Объявление регистра выглядит так
зарегистрировать int x;
зарегистрировать символ c;
Чтобы было ясно, я просто надеюсь увидеть несколько классных примеров кода. Я (почти уверен, что я) понимаю предмет, поэтому не чувствую необходимости вводить подробное объяснение (если вы этого не хотите).
6 ответов
Нет хорошего примера использования регистра при использовании современных компиляторов (читай: последние 15 с лишним лет), потому что он почти никогда не приносит пользы и может приносить вред. Когда вы используете register, вы говорите компилятору: "Я знаю, как оптимизировать мой код лучше, чем вы", что почти никогда не происходит. Когда вы используете реестр, может произойти одно из трех:
- Компилятор игнорирует это, это наиболее вероятно. В этом случае единственный вред состоит в том, что вы не можете получить адрес переменной в коде.
- Компилятор учитывает ваш запрос, и в результате код работает медленнее.
- Компилятор выполняет ваш запрос, и код выполняется быстрее, это наименее вероятный сценарий.
Даже если один компилятор создает лучший код при использовании регистра, нет никаких оснований полагать, что другой будет делать то же самое. Если у вас есть какой-то критический код, который компилятор недостаточно хорошо оптимизирует, лучше всего в любом случае, вероятно, использовать ассемблер для этой части, но, конечно, сначала выполните соответствующее профилирование, чтобы убедиться, что сгенерированный код действительно является проблемой.
В целом я согласен с Робертом, но, как и в любом хорошем правиле, в этом есть и исключения.
Если вы работаете с глубоко встроенной системой, вы можете лучше, чем компилятор, знать, как оптимизировать код для вашего конкретного приложения на вашей конкретной аппаратной архитектуре.
Но в 99% случаев объяснение Робертса хорошо и для встроенного слова.
Я знаю, что это довольно давно, но здесь есть реализация подпроцедуры из heapsort, в которой использование переменных реестра ускоряет алгоритм, по крайней мере, с помощью gcc 4.5.2 для компиляции кода.
inline void max_heapify(int *H, int i){
char OK = FALSE;
register int l, r, max, hI;
while(!OK){
OK = TRUE;
l = left(i);
r = right(i);
max = i;
if(l <= H[SIZE] && H[l] > H[i]){
max = l;
}
if(r <= H[SIZE] && H[r] > H[max]){
max = r;
}
if(max != i){
OK = FALSE;
hI = H[i];
H[i] = H[max];
H[max] = hI;
i = max;
}
}
}
Я протестировал алгоритм с и без ключевого слова register перед атрибутами и выполнил его, чтобы отсортировать случайный массив с 50 000 000 элементов в моей записной книжке, несколько раз для каждой версии.
использование регистров сократило время сортировки с ~135 до ~125 с.
Я также протестировал только 5 000 000 элементов, но выполнил его еще раз.
Версия без регистра начиналась в 11 с, но каждое исполнение уменьшало время до 9,65 с и останавливалось на этом.
версия с регистром началась в 10 секунд и снизила время до 8,80 секунд.
Я думаю, что это как-то связано с кеш-памятью. Тем не менее, кажется, что регистры ускоряют алгоритм за счет постоянного фактора
Поскольку эти переменные довольно часто используются в алгоритме, то, гарантируя, что они включены в регистр, вместо того, чтобы оставлять эту работу компилятору, в этом случае был достигнут лучший результат. Однако это не сильно улучшило время.
Надеюсь, что это будет полезно для кого-то, привет.
Другой распространенный случай - реализация низкоуровневых интерпретаторов. Сохранение некоторого состояния в регистрах, например. указатель стека виртуальной машины, может значительно уменьшить доступ к памяти и ускорить ваш код.
См. Vmgen - генератор эффективных интерпретаторов виртуальных машин для примера оптимизации (5.2 Кэширование в верхней части стека).
Во-первых, переменная регистра должна использоваться для часто используемых переменных, таких как переменная управления циклом, для повышения производительности за счет минимизации времени доступа. вторичный, вы можете использовать только и только зарегистрировать спецификатор хранилища в этой ситуации, например, fun (auto int a,auto int b): fun fun (зарегистрируйте int a, зарегистрируйте int b): правильно только это будет работать fun (static int a,static int b): забава ошибки (extern int a,extern int b): ошибка
Ну, это вопрос, требующий нескольких ответов, потому что существует несколько контекстов кодирования: с точки зрения языка высокого уровня, среднего и низкого уровня (вплоть до сборки), поскольку язык C может вызывать процедуры сборки.
Причиной использования сборки вместо C является исключительно из-за проблем с производительностью, возникающих во время разработки, так что да, есть необходимость в ключевом слове register, но во многих случаях оно не работает так, как задумано разработчиком.