Какой хороший пример использования переменной регистров в C?
Я читаю K & R и приходил в небольшой раздел о переменных регистра, и задавался вопросом, есть ли у людей здесь хорошие примеры того, как это реализовано на практике.
Из раздела 4.7 в K & R:
Объявление регистра выглядит так: register int x;
register char c;
Чтобы быть ясным, я просто надеюсь увидеть интересные примеры кода. Я (довольно уверен, что я) понимаю предмет, поэтому не чувствую необходимости вводить подробное объяснение (если вы этого не хотите).
Ответы
Ответ 1
Нет хорошего примера использования регистров при использовании современных компиляторов (читай: последние 15+ лет), потому что он почти никогда не делает ничего хорошего и может сделать что-то плохое. Когда вы используете регистр, вы сообщаете компилятору "Я знаю, как оптимизировать код лучше, чем вы", что почти никогда не бывает. Одна из трех вещей может произойти, если вы используете регистр:
- Компилятор игнорирует это, это наиболее вероятно. В этом случае единственный вред в том, что вы не можете взять адрес переменной в коде.
- Компилятор выполняет ваш запрос, и в результате код работает медленнее.
- Компилятор отличает ваш запрос, и код работает быстрее, это наименее вероятный сценарий.
Даже если один компилятор создает лучший код, когда вы используете регистр, нет оснований полагать, что другой сделает то же самое. Если у вас есть критический код, который компилятор недостаточно оптимизирует, ваш лучший выбор, вероятно, будет использовать ассемблер для этой части в любом случае, но, конечно же, соответствующее профилирование для проверки сгенерированного кода действительно является проблемой в первую очередь.
Ответ 2
В общем, я согласен с Robert, но, как и любое хорошее правило, у этого есть исключения.
Если вы работаете над глубоко внедренной системой, вы можете лучше узнать компилятор, как оптимизировать код для вашего конкретного приложения на вашей конкретной аппаратной архитектуре.
Но в 99% случаев объяснение Робертса полезно для встроенного слова.
Ответ 3
Я знаю, что это происходит довольно давно, но вот реализация подпроцедуры из 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;
}
}
}
Я тестировал algortihm с и без ключевого слова register перед атрибутами и выполнял его для сортировки случайного массива с 50 000 000 элементов на моем ноутбуке, несколько раз для каждой версии.
использование регистров сократило время от времени от момента от 135 до 125 секунд.
Я также тестировал только 5 000 000 элементов, но выполнял его больше раз.
Версия без регистра началась в 11 секунд, но каждое исполнение уменьшило время до достижения 9,65 с и остановилось на нем
версия с регистром, начатым в 10 с и опустившим время до 8,80 с.
Я думаю, что это имеет какое-то отношение к кэш-памяти. Тем не менее, кажется, что регистры ускоряют алгоритм с помощью константного фактора
Поскольку эти переменные довольно часто используются по алгоритму, гарантируя, что они находятся в регистре, вместо того, чтобы оставить эту работу компилятору, привел к лучшему результату в этом случае. Однако это не улучшило время.
Надеюсь, это будет полезно кому-то, привет.
Ответ 4
Другим распространенным случаем является внедрение низкоуровневых переводчиков. Сохранение некоторого состояния в регистрах, например. указатель стека виртуальной машины, значительно сократит доступ к памяти и ускорит ваш код.
См. vmgen - генератор эффективных интерпретаторов виртуальных машин для примера оптимизации (5.2 К началу кэширования стека).
Ответ 5
во-первых, переменная регистра должна использоваться для сильно используемых переменных, таких как переменная управления контуром, для повышения производительности за счет минимизации времени доступа. вторичный, вы можете использовать только и только регистрировать спецификатор хранилища в этой ситуации
например, fun (auto int a, auto int b): ошибка fun (register int a, register int b): право только это будет запущено fun (static int a, static int b): ошибка fun (extern int a, extern int b): ошибка