Какой хороший пример использования регистровых переменных в C?
-
10-07-2019 - |
Вопрос
Я читаю K & R и наткнулся на небольшой раздел о регистровых переменных, и мне стало интересно, есть ли у людей здесь какие-нибудь хорошие примеры применения этого на практике.
Из раздела 4.7 в K & R:
Объявление регистра выглядит следующим образом
зарегистрировать int x;
зарегистрировать символ c;
Чтобы было понятно, я просто надеюсь увидеть несколько интересных примеров кода.Я (почти уверен, что я) разбираюсь в предмете, поэтому не считаю нужным вводить подробное объяснение (если вы этого не хотите).
Решение
Нет хорошего примера использования регистра при использовании современных компиляторов (читать:последние 15 с лишним лет), потому что это почти никогда не приносит никакой пользы и может принести немного вреда.Когда вы используете register, вы говорите компилятору: "Я знаю, как оптимизировать свой код лучше, чем вы", чего почти никогда не бывает.При использовании register может произойти одна из трех вещей:
- Компилятор игнорирует его, это наиболее вероятно.В этом случае единственный вред заключается в том, что вы не можете использовать адрес переменной в коде.
- Компилятор выполняет ваш запрос, и в результате код выполняется медленнее.
- Компилятор выполняет ваш запрос, и код выполняется быстрее, это наименее вероятный сценарий.
Даже если один компилятор выдает лучший код при использовании 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 секунд.
Я думаю, что это как-то связано с кеш-памятью. Тем не менее, кажется, что регистры ускоряют алгоритм благодаря постоянному коэффициенту
Поскольку эти переменные довольно часто используются в алгоритме, то, гарантируя, что они находятся в регистре, вместо того, чтобы оставлять эту работу компилятору, в этом случае был достигнут лучший результат. Тем не менее, это не сильно улучшило время.
Надеюсь, что это будет полезно для кого-то, привет.
Другой распространенный случай - реализация низкоуровневых интерпретаторов. Сохранение некоторого состояния в регистрах, например. указатель стека виртуальной машины, может значительно уменьшить доступ к памяти и ускорить ваш код.
Ну, это вопрос, требующий нескольких ответов, потому что существует несколько контекстов кодирования: с точки зрения языка высокого уровня, среднего уровня и низкого уровня (вплоть до сборки), поскольку язык C может вызывать процедуры сборки.
Причиной использования сборки вместо C является просто причина в проблемах производительности, возникающих во время разработки, так что да, существует необходимость в ключевом слове register, но во многих случаях оно не работает так, как задумывалось разработчиком