Что является хорошим примером использования переменной регистра в 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, но во многих случаях оно не работает так, как задумано разработчиком.

Другие вопросы по тегам