Как может быть так много регистровых переменных с таким ограниченным количеством регистров?

Я дурачился с C и понял, по праву, если я объявлю кучу переменных регистра, не будут ли значения перезаписаны? Из того, что я могу сказать из сборки, в микропроцессоре нет тонны регистров, недостаточно для удовлетворения созданного мною требования. Как С сохраняет все значения?

5 ответов

Старый компилятор выделил бы столько регистров register переменные, как они могли (в некоторых случаях это число было 0) и выделить остальные переменные в стеке.

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

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

Там нет требования, что все переменные объявлены с register должны храниться в регистрах процессора.

Вот что говорит стандарт C:

Объявление идентификатора для объекта с регистром спецификатора класса хранения предполагает, что доступ к объекту должен быть максимально быстрым. Степень эффективности таких предложений определяется реализацией.

Ссылка: проект ISO C11 N1570, пункт 6.7.1, пункт 6. Обратите внимание, что в нем даже не упоминаются регистры процессора.

Соответствующий компилятор может просто игнорировать все register ключевые слова (кроме наложения некоторых ограничений на взятие адреса register объекты).

На практике большинство компиляторов просто помещают столько register переменные в регистрах процессора, как они могут.

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

В наши дни принято считать, что register Ключевое слово не дает много пользы.

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


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

С https://en.cppreference.com/w/c/language/storage_duration

Спецификатор регистра допускается только для объектов, объявленных в области видимости блока, включая списки параметров функции. Он указывает продолжительность автоматического хранения и отсутствие связи (что является значением по умолчанию для объявлений такого рода), но дополнительно намекает оптимизатору сохранить значение этой переменной в регистре ЦП, если это возможно. Независимо от того, происходит эта оптимизация или нет, объявленные переменные register не могут использоваться в качестве аргументов оператора address-of, не могут использовать функции alignas (начиная с C11), а массивы регистров не конвертируются в указатели.

В течение многих лет он ничего не делал: оптимизирующие компиляторы уже по возможности сохраняют переменные в regs. Для переменных, которые являются глобальными или имеют адрес, взятый, тогда, возможно, только для части функции, сохраняя результат обратно в память, если переменная не может быть оптимизирована.


КСТАТИ, register был официально объявлен устаревшим в C++, а C++17 фактически удалил его из языка. https://en.cppreference.com/w/cpp/language/storage_duration.


Связанный: GNU C имеет register int foo asm("eax"); (или любой другой регистр), но даже это гарантированно будет иметь эффект только при использовании в качестве операнда для оператора inline-asm при использовании для локальных переменных. В текущих версиях GCC это заставляет компилятор использовать этот регистр для переменной, если только ему не нужно разлить / перезагрузить его, чтобы складывать память между вызовами функций или чем-то еще.

https://gcc.gnu.org/onlinedocs/gcc/Local-Register-Variables.html

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

C был разработан, чтобы позволить компилятору генерировать ассемблерный код для функции во время ее синтаксического анализа, вместо того, чтобы читать всю функцию, проверять ее, а затем генерировать код впоследствии. Компилятор, который проанализировал программу настолько, насколько:

int test(void)
{
  int x=0,y=0;
  int *p = &y;

  while(x < 10)
  {
    x++;
    foo();
    x++;
    *p *= 3;
    x++;
    bar();
    ...

не было бы никакого способа узнать, является ли значение x может быть безопасно храниться в реестре через вызов foo и / или операция на *p или это может быть возможно для foo изменить значение x,

Цель register Ключевым словом было эффективно сообщить компилятору, что было бы безопасно хранить значение объекта в регистре между вызовами функций или операциями, которые пишут в указатели, даже если он не видел всего, что код может делать с объектом. Такое значение может быть полезно даже сегодня, если передача адреса объекта во вложенную функцию не является нарушением ограничения, но компилятору было разрешено предполагать, что в любом контексте, где используется именованный объект lvalue, все операции будут включать в себя этот именованный -объект Если адрес объекта никогда не берется, для приглашения такого предположения не потребуется никакой классификатор, но в тех случаях, когда адрес объекта берется, но не сохраняется в конфликтующих операциях, связанных с объектом, такой классификатор может дать информацию компилятора, в противном случае он не будет иметь.

Переменные обычно хранятся в стеке. То есть блок памяти. Значение переменной обычно загружается в регистр для манипуляции и перемещается обратно в стек (сохраняется), если требуется манипулировать другой переменной. Часто переменная даже не загружается в регистр, она обрабатывается в стеке.

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