C: Адрес в регистре или памяти? - PullRequest
0 голосов
/ 11 мая 2018

Я немного смущен ключевым словом "регистр" в C. Кажется, он говорит компилятору, что он должен храниться в регистре, что означает, что некоторые из моих переменных хранятся в регистрах, а некоторые в памяти? Если да, есть ли способ узнать, хранится ли мое значение в регистре или в памяти?

Например:

int *x =  (int*) 0x1234;

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

Итак, мой главный вопрос: как выглядит адрес в указателе, когда он указывает на регистр?

РЕДАКТИРОВАТЬ: Я не могу найти ответ на мой главный вопрос в конце моего вопроса в другом вопросе. Мой вопрос НЕ о ключевом слове "регистрация", я только что упомянул его.

Ответы [ 4 ]

0 голосов
/ 11 мая 2018

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

Спецификатор класса хранения register является одним из них.Итак, давайте начнем смотреть на спецификации, прежде чем комментировать их.

Из ИСО / МЭК 9899: 2011 , стандарт C11:

§6.7.1Спецификаторы класса хранения

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

И примечание 119:

ПРИМЕЧАНИЕ

Реализация может обрабатывать любое объявление регистра просто какавто декларация.Однако независимо от того, используется ли адресное хранилище на самом деле, адрес любой части объекта, объявленной с помощью регистра спецификатора класса хранилища, не может быть вычислен ни явно, ни с помощью унарного оператора &, как описано в 6.5.3.2), илинеявно (путем преобразования имени массива в указатель, как описано в 6.3.2.1).Таким образом, единственным оператором, который можно применить к массиву, объявленному с помощью регистра спецификатора класса хранения, является sizeof.

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

В последнем случае технически возможно получить адрес хранилища, но это явно запрещено стандартом, как описано в примечании, нотакже применяется в ограничениях из §6.5.3.2 Операторы адреса и косвенности :

Операнд унарного оператора & должен быть либо функциейуказатель, результат [] или унарного * оператора или lvalue, который обозначает объект, который не является битовым полем и не объявляется с помощью register спецификатора класса хранения .

Конечно, некоторые несовместимые компиляторы могут позволить вам применить оператор.

Теперь вернемся к самому вашему вопросу:

  1. int *x = (int*) 0x1234; X сейчас, похоже, не указывает на регистр, потому что такие адреса предназначены для памяти.Но я несколько раз пытался найти другой выглядящий адрес (также используя ключевое слово «register»).Даже в Интернете, кажется, никого не волнует.

Ваш пример неверен , вы объявляете указатель на int и присваиваете ему произвольный адрес,Это не имеет никакого отношения к спецификатору хранения register.

Объявите register int *x = (int*) 0x1234;, а затем попробуйте применить оператор & к x, как в int **pp = &x; (обратите внимание, что мы объявляем указатель науказатель на int, это то, что мы получаем, взяв адрес указателя на int).

Вы получите ошибку на совместимых компиляторах.

Итак, мой главный вопрос: как выглядит адрес в указателе, когда он указывает на регистр?

Ответ прост: ничего не напоминает, потому что не может существовать в стандарте C .

0 голосов
/ 11 мая 2018

В большинстве архитектур вы не можете указывать на регистр ЦП, поскольку они не отображены в памяти. (8051 - это одна архитектура, которую я могу себе представить, где регистры ядра отображены в память).

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

volatile int* x =  (volatile int*)0x1234 ;

Ключевое слово register не имеет ничего общего с отображенной в память периферийными регистрами .

0 голосов
/ 11 мая 2018

Как выглядит адрес в указателе, когда он указывает на регистр?

Указатели - это концепция памяти, регистры не имеют адресов.Каждый процессор имеет ограниченное, фиксированное количество регистров (вероятно, 8-16).

Как уже упоминали другие, register на самом деле больше не используется и даже иногда игнорируется компиляторами.

Чтобы понять, что на самом деле представляют собой регистры, рассмотрим следующий пример:

int a = k / 53;  // k is an int defined somewhere else...
int b = a * 9;
// a is not used after the above line

Теперь мы не объявили a с register, но любой разумный компилятор все равно будет хранить a в регистре..

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

Для вычисления a из приведенного выше примера компилятор напишет код для загрузки k (который предположительнонаходится в памяти) в определенный регистр (назовем его регистром A), а 53 - в другой.После того, как вычисления выполнены, регистр A будет содержать результат операции.Так как в любом случае мы собираемся умножить этот результат на девять в следующей строке, мы можем просто сохранить его, загрузить 9 в другой регистр и умножить.Сохранение значения в памяти и последующая загрузка его в регистр просто потратят много времени.

Обратите внимание, что объявление a с volatile предотвратит подобные оптимизации и заставит компилятор на самом деле хранить инагрузка a.(Хотя volatile здесь не имеет никакого смысла в этом примере, и вряд ли когда-нибудь пригодится, если вы, например, не взаимодействуете со специальным оборудованием).

0 голосов
/ 11 мая 2018

В современных компиляторах объект, который вы объявляете в C, не обязательно имеет единственное местоположение, в котором он существует. Чтобы оптимизировать вашу программу, компилятор может иногда хранить ее в регистре, в стеке в других или в определенной области памяти в других. Обычно вам не нужно знать, какие именно.

Когда вы берете адрес объекта и работаете с указателями, компилятор заставляет вашу программу работать так, как будто объект имеет фиксированный адрес. Зачастую это делается путем помещения объекта в назначенную ячейку памяти, по крайней мере, на время, в течение которого вы используете его адрес, но компилятору разрешено достигать конечных результатов вашей программы другими способами.

Если вы объявляете объект с register, вы не должны, по стандарту C, брать его адрес. Однако некоторые компиляторы могут разрешить это.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...