Я читал K&R и дошел до небольшого раздела, посвященного регистровым переменным, и мне было интересно, есть ли здесь у людей какие-нибудь хорошие примеры этого на практике.
Из раздела 4.7 в K&R:
The register declaration looks like
register int x;
register char c;
Чтобы быть ясным, я просто надеюсь увидеть несколько интересных примеров кода. Я (почти уверен, что я) понимаю предмет, поэтому не чувствую необходимости вводить подробное объяснение (если вы этого не хотите).





Нет хорошего примера использования регистров при использовании современных компиляторов (читай: последние 15+ лет), потому что это почти никогда не приносит пользы и может принести вред. Когда вы используете регистр, вы говорите компилятору: «Я знаю, как оптимизировать свой код лучше, чем вы», чего почти никогда не бывает. Когда вы используете регистр, может произойти одно из трех:
Даже если один компилятор создает лучший код, когда вы используете регистр, нет оснований полагать, что другой будет делать то же самое. Если у вас есть какой-то критический код, который компилятор не оптимизирует достаточно хорошо, лучше всего, вероятно, использовать ассемблер для этой части, но, конечно, сделайте соответствующее профилирование, чтобы убедиться, что сгенерированный код действительно является проблемой в первую очередь.
Помните, что компилятор совершенно свободен проигнорировать ваше предложение - в стандарте нет ничего, что говорило бы, что он должен помещать регистровую переменную в регистр.
также может быть случай, если вы пишете бэкэнд компилятора и говорите «зарегистрировать» для всех локальных переменных в функции, что сделает функцию без стека. это было бы весьма полезно, я думаю.
хотя в этом случае __attribute __ ((register_function)) или тому подобное было бы лучше, я думаю
Этот ответ оказал большое влияние. Подавляющее большинство объявлений регистров было удалено из кода Perl., со ссылкой на этот ответ.
Этот ответ вводит в заблуждение. Ключевое слово register касается не аппаратных регистров, а оптимизации. Единственный его эффект состоит в том, что адрес такой переменной не может быть получен. В частности, его можно использовать для создания псевдонимов переменных, что может быть весьма полезно.
Это не вводит в заблуждение, это совершенно неправильно. Соответствующий компилятор не могу игнорирует register: получение адреса переменной недопустимо, он не может это игнорировать. Это единственное, что делает ключевое слово: генерирует дополнительные проверки и ошибки, чтобы помочь люди.
@Leushenko: Интересно, было бы полезно иметь типы "указатель на значение с указанием регистра", чтобы void foo(int register *p); гарантировал, что p не будет сохраняться после вызова функции, а int scanf(char const *fmt, register ...) будет гарантировать, что указатели не будут переданы как переменные аргументы будет сохраняться. Тогда компилятор может сделать register int i; scanf("%d", &i); эквивалентом register int i; int temp; scanf("%d", &temp); i=temp;, но ему будет разрешено опускать временный интервал, когда он ему не нужен.
В целом я согласен с Роберт, но, как и в любом хорошем правиле, у этого есть исключения. Если вы работаете над глубоко встраиваемой системой, возможно, вы лучше компилятора знаете, как оптимизировать код для ваше конкретное приложение на вашей конкретной аппаратной архитектуре.
Но в 99% случаев объяснение Робертса подходит и для вложенного слова.
Честно говоря, это очень похоже на то, что сказал Роберт.
Вообще-то ты вроде и прав. Я перечитал сообщение, и последний абзац разъясняет то, что я хотел уточнить ... В следующий раз я буду читать получше
Другой распространенный случай - реализация низкоуровневых интерпретаторов. Сохранение некоторого состояния в регистрах, например. указатель стека виртуальной машины, может значительно уменьшить доступ к памяти и ускорить код.
См. Пример оптимизации в vmgen - генератор эффективных интерпретаторов виртуальных машин (5.2 Верхнее кэширование стека).
Во-первых, регистровую переменную следует использовать для часто используемых переменных, таких как переменная управления циклом, чтобы повысить производительность за счет минимизации времени доступа. вторичный вы можете использовать только и только регистрировать спецификатор хранилища в этой ситуации вроде бы весело (auto int a, auto int b): ошибка весело (зарегистрируйте int a, зарегистрируйте int b): правильно, только это будет запущено fun (static int a, static int b): ошибка fun (extern int a, extern int b): ошибка
Какие?! Текст K&R относится к 1970-м годам, поэтому некоторые из их рекомендаций немного устарели. Использование register, безусловно, одно из таких.
Я знаю, что это довольно давно, но вот реализация подпроцедуры из 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 с.
Я думаю, это как-то связано с кеш-памятью. Тем не менее, кажется, что регистры ускоряют алгоритм за счет постоянного фактора.
Поскольку эти переменные довольно часто используются в алгоритме, обеспечение их наличия в регистре вместо того, чтобы оставлять эту работу компилятору, привело к лучшему результату в этом случае. Однако это не сильно улучшило время.
Надеюсь, это будет кому-нибудь полезно, привет.
Чтобы серьезно относиться к тестированию, вы должны предоставить информацию о том, как вы его скомпилировали (какие флаги), на какой платформе вы это сделали, и, возможно, некоторые подробности о вашей архитектуре и / или процессоре. Также важно, как вы запускали max_heapify.
Что ж, это вопрос, на который нужно несколько ответов, потому что существует несколько контекстов кодирования: с точки зрения языка высокого уровня, среднего и низкого уровня (вплоть до сборки), поскольку язык C может вызывать процедуры сборки.
Причина использования сборки вместо C явно связана с проблемами производительности, возникающими во время разработки, поэтому да, есть необходимость в ключевом слове register, но нет, во многих случаях он не работает так, как задумано разработчиком
«Три вещи могут случиться, а две - плохо»? Где я такое слышал раньше ... ;-)