Какой хороший пример использования регистровой переменной в C?

Я читаю K&R и наткнулся на небольшой раздел, посвященный регистровым переменным, и мне было интересно, есть ли у людей здесь хорошие примеры того, как это реализовано на практике.

Из раздела 4.7 в K&R:

Объявление регистра выглядит следующим образом:
register int x;
register char c;

Чтобы было ясно, я просто надеюсь увидеть несколько крутых примеров кода. Я (почти уверен, что я) понимаю предмет, поэтому не чувствую необходимости печатать подробное объяснение (если вы этого не хотите).


person Community    schedule 24.11.2008    source источник


Ответы (6)


Нет хорошего примера использования регистров при использовании современных компиляторов (читай: последние 15+ лет), потому что это почти никогда не приносит пользы, а может и плохо. Когда вы используете регистр, вы говорите компилятору: «Я знаю, как оптимизировать свой код лучше, чем вы», что почти никогда не бывает. При использовании register может произойти одна из трех вещей:

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

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

person Robert Gamble    schedule 24.11.2008
comment
Три вещи могут случиться, а две — плохо? Где я это уже слышал... ;-) - person Steve Jessop; 25.11.2008
comment
Помните, что компилятор может совершенно свободно игнорировать ваше предложение - в стандарте ничего не говорится о том, что он должен помещать регистровую переменную в регистр. - person Martin Beckett; 14.12.2008
comment
также может быть случай, когда вы пишете серверную часть компилятора, и вы говорите, что регистрация для всех локальных переменных в функции сделает функцию без стека. это было бы весьма полезно, я думаю. - person Johannes Schaub - litb; 14.12.2008
comment
хотя в этом случае __attribute__((register_function)) или тому подобное было бы лучше, я думаю - person Johannes Schaub - litb; 14.12.2008
comment
Довольно большое влияние этот ответ оказал. Подавляющее большинство объявлений регистров было удалено из кода Perl со ссылкой на этот ответ. - person Palec; 11.08.2014
comment
Этот ответ вводит в заблуждение. Ключевое слово register относится не к аппаратным регистрам, а к оптимизации. Его единственный эффект заключается в том, что адрес такой переменной нельзя взять. В частности, его можно использовать для присвоения псевдонимов переменных, что может быть очень полезно. - person Jens Gustedt; 24.07.2015
comment
Это не заблуждение, это в корне неверно. Соответствующий компилятор не может игнорировать register: получение адреса переменной недопустимо, он не может игнорировать это. Это единственное, что делает ключевое слово: генерирует дополнительные проверки и ошибки, чтобы помочь людям. - person Leushenko; 30.08.2015
comment
@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;, но ему было бы разрешено опустить временную переменную, когда она ему не нужна. - person supercat; 28.01.2016

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

Но в 99% случаев объяснение Роберта годится и для встроенного слова.

person Community    schedule 24.11.2008
comment
Честно говоря, это очень похоже на то, что сказал Роберт. - person Jonathan Leffler; 24.11.2008
comment
Вообще-то ты прав. Я перечитал пост, и последний абзац разъясняет то, что я хотел уточнить... В следующий раз я буду читать лучше - person Ilya; 24.11.2008

Я знаю, что это было довольно давно, но вот реализация подпроцедуры из 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с.

Я думаю, что это как-то связано с кэш-памятью. Тем не менее кажется, что регистры ускоряют алгоритм в постоянном множителе.

Поскольку эти переменные довольно часто используются в алгоритме, обеспечение их регистрации вместо того, чтобы возлагать эту работу на компилятор, привело к лучшему результату в этом случае. Однако это не сильно улучшило время.

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

person Community    schedule 15.06.2013
comment
Чтобы серьезно отнестись к бенчмаркингу, вы должны предоставить информацию о том, как вы его скомпилировали (какие флаги), на какой платформе вы его проводили и, возможно, некоторые подробности о вашей архитектуре и/или процессоре. То, как вы запускали max_heapify, тоже важно. - person raylu; 02.07.2014

Другой распространенный случай — реализация низкоуровневых интерпретаторов. Сохранение некоторого состояния в регистрах, например. указатель стека виртуальной машины может значительно сократить доступ к памяти и ускорить код.

См. vmgen — генератор эффективные интерпретаторы виртуальных машин для примера оптимизации (5.2 Кэширование поверх стека).

person Community    schedule 13.12.2008

во-первых, переменная регистра должна использоваться для часто используемых переменных, таких как переменная управления циклом, чтобы повысить производительность за счет минимизации времени доступа. вторично вы можете использовать только и только регистровый спецификатор хранилища в этой ситуации, например, fun (auto int a, auto int b): error fun (register int a, register int b): правильно, только это будет запускать fun (static int a, статический int b) :error fun (extern int a,extern int b) :error

person Community    schedule 05.01.2013
comment
Какая?! Текст K&R относится к 1970-м годам, поэтому некоторые из их рекомендаций немного устарели. Использование register определенно является одним из них. - person Bo Persson; 05.01.2013

Ну, это вопрос, который требует нескольких ответов, потому что существует несколько контекстов кодирования: с точки зрения языка высокого уровня, среднего уровня и низкого уровня (вплоть до ассемблера), поскольку язык C может вызывать подпрограммы ассемблера.

Причина использования сборки вместо C заключается исключительно в проблемах с производительностью, возникающих во время разработки, так что да, ключевое слово register необходимо, но нет, во многих случаях он не работает так, как задумал разработчик.

person Community    schedule 21.10.2018