Адрес переменной регистра
В C мы не можем использовать и узнать адрес переменной регистра, но в С++ мы можем сделать то же самое. Почему это законно в С++, но не в C? Может кто-то, пожалуйста, объясните эту концепцию в глубину.
Ответы
Ответ 1
Здесь выдержка из раздела 6.7.1 (примечание 101) стандарт C99 (pdf):
Реализация может рассматривать любое объявление register
просто как объявление auto
. Однако независимо от того, используется ли адресное хранилище или нет, адрес любой части объекта, объявленного с помощью регистра спецификатора класса хранения, не может быть вычислен явно (с использованием унарного оператора &
as обсуждается в 6.5.3.2) или неявно (путем преобразования имени массива в указатель, как описано в 6.3.2.1). Таким образом, единственным оператором, который может быть применен к массиву, объявленному спецификатором класса хранения register
, является sizeof
.
И из раздела 7.1.1, абзац 3 стандарт С++ (pdf):
A register
specifier имеет ту же семантику, что и спецификатор auto
, вместе с подсказкой к реализации, которую объявленный объект будет сильно использоваться. [Примечание: подсказка может быть проигнорирована, и в большинстве реализаций она будет игнорироваться, если будет сделан адрес объекта. -end note]
Веселые лакомые кусочки о register
Группа С++ (WG21) хочет отказаться от register
:
Ключевое слово register
выполняет очень мало функций, предлагая не более чем намек на то, что примечание обычно игнорируется. Он должен быть устаревшим в этой версии стандарта, освободив зарезервированное имя для использования в будущем стандарте, подобно тому, как auto
был повторно использован на этот раз для того, чтобы быть таким же бесполезным.
Примечания к встрече в марте 2009 года:
Консенсус КГР был в пользу обесценивания register
.
Посмотрите, что группа C99 (WG14) рассказала о register
(pdf) на встрече:
Общее соглашение об отказе от ключевого слова "auto
". Если мы попросим РГ21 вернуться к предыдущее использование "register
" (без адреса)? Нет, это не будет летать с WG21.
Ответ 2
Ключевое слово register - только подсказка и может быть проигнорирована. Большинство компиляторов С++ игнорируют его все время, но любой компилятор С++ игнорирует его, если вы берете адрес переменной или создаете ссылку на него.
С другой стороны, компилятор С++ не должен игнорировать "регистр" только потому, что вы берете адрес переменной. Теоретически компилятор мог бы хранить его в регистре и давать вам какое-то волшебное значение указателя, которое каким-то образом отображается в регистре за кулисами, но это было бы очень полезно для очень небольшого выигрыша, поэтому никакой компилятор (что я знаю) делает что-то подобное.
Поскольку регистр также игнорируется в C, я подозреваю, что явное запрещение на использование адресов регистрационных переменных было просто для облегчения компиляторов C из бремени проверки для этого.
Соответствующая часть стандарта С++ - это 7.1.1.3:
Спецификатор регистра имеет ту же семантику, что и авто-спецификатор, вместе с подсказкой к реализации, которую объявленный объект будет сильно использоваться. [Примечание: подсказка может быть проигнорирована, и в большинстве реализаций она будет игнорироваться, если будет сделан адрес объекта. -end note]
Ответ 3
Извините за сверхсрочный ответ.
Проблема заключается в том, что в C, register
изначально означало сохранение значений в регистре, поэтому для него могут использоваться только int
и char
. Но со временем и особенно стандартным С++ он расширился до "быстрого доступа", а не "в регистре CPU".
Поэтому в С++ массив может иметь тип register
, но мы знаем, что хранить массивы в регистре CPU невозможно. Следовательно, логически нормально обращаться к регистру С++ (в указанном выше смысле), но все равно не имеет смысла, если значения фактически находятся в регистре CPU.
Ответ 4
Я предполагаю, что ключевое слово не могло бы даже превратить его в язык, если бы не совместимость с C. Хотя я не могу говорить с какими-либо полномочиями, если это так, мне кажется, что существует практическая причина для того, чтобы он был законным, за исключением стандартного предложения "компилятор умнее вас": С++ принимает адреса вещей без разрешение более легко, чем C. В частности: функции-члены и ссылки.
Поскольку функции-члены требуют неявного параметра this
, было бы невозможно вызвать их из объявленного объекта register
. В C нет ничего запрещающего вам говорить register struct X x;
, поэтому такой язык должен быть разрешен в С++ [поскольку C-совместимость - это вся причина, по которой ключевое слово существует даже). Но если вы запрещаете вызывать функции-члены, а также принимать адреса, это также относится к первому вызову конструктора. По сути, он не будет работать на не-POD-типах. Таким образом, вы получаете один спецификатор класса хранения, который действителен только для небольшого подмножества правовых типов, когда все остальное можно использовать для чего угодно.
Вы также не могли создавать ссылки на такие объекты, хотя технически компилятор не должен рассматривать ссылки в качестве указателей. register int i; int& x;
не требуется иметь место для двух переменных, но если вы позже сделаете &x
, вы получите указатель на i
. Таким образом, первоначальная конструкция должна быть незаконной. Хотя это похоже на не-проблему, поскольку ссылки вообще не существуют в C, возвращаясь к нашей предыдущей точке, типы POD, объявленные с помощью спецификатора register
, больше не могут быть скопированы. Конструктор копии, предоставленный компилятором, имеет форму X::X(const X&)
или X::X(X&)
.
Итак, чтобы поддерживать совместимость с C, они должны сделать register
уникальным как спецификатор класса хранения, поскольку он не применяется ко всем типам и модифицирует по крайней мере две разные части стандарта в другом месте [указать, что вы не можете создать ссылку на переменную, объявленную с помощью спецификатора register
, и каким-то образом обработать ссылки для копирования POD]. Или они могли просто сказать "все в порядке, чтобы принять адрес", и пусть составители решают, выполнять или не выполнять запросы. Что-то они планировали делать так или иначе.
Ответ 5
Регистровая переменная не имеет адреса, она удерживается (по крайней мере, она должна быть сохранена) в регистре процессора. Поскольку модификатор регистра - не что иное, как подсказка, если вы вынуждаете компилятор генерировать код для извлечения его адреса, модификатор будет проигнорирован, и вы получите обычную переменную, хранящуюся в памяти.
Чтобы напрямую ответить на ваш вопрос, в зависимости от того, какой из них позволяет вам принять адрес переменной регистра (ваш исходный пост противоречит самому себе), вы можете игнорировать свой собственный намек и, по крайней мере, выдать предупреждение. ИМО правильной реализацией было бы запретить обращение к регистру переменной.
Ответ 6
Важно помнить, что "регистр" - это всего лишь подсказка для компилятора (бессмысленно, я никогда не видел улучшения скорости, и большинство компиляторов, вероятно, просто игнорируют его). C и С++ позволяют игнорировать ваш "совет" и сохранить переменную в памяти. Конечно, если вы берете адрес переменной, это заставит его назначить место в памяти.
C и С++ имеют разные правила о том, что вы можете сделать, потому что они разные языки. Разработчики С++ решили разрешить вам получить адрес переменной регистра, потому что это ничего не повредит; C не позволяет вам это делать, потому что это заставит его в памяти.
Подумав об этом больше, ограничение C, вероятно, по той же причине, что переменные должны были быть объявлены в начале блока — компилятор может компоновать память для переменных по мере их столкновения, независимо от того, как она используется позже в функция.
Ответ 7
C и С++ - это два разных языка с большим общим подмножеством. Вот почему между ними разные вещи.
Пока я не понимаю ваш вопрос, register
- это (по крайней мере, на С++) намек на то, что доступ к переменной можно получить чаще, и ничего более. В C это означает, что вы не можете взять адрес с унарным оператором &
, который в то время сделал определенный смысл. В первые дни C ожидалось, что компилятор может не беспокоить выделение памяти для переменной, и поэтому необязательно должен быть адрес, который нужно принять.
(Обычно компьютеры имеют регистры, которые являются частями быстрого доступа к ЦП и, следовательно, являются самым быстрым хранилищем для доступа. Переменная может находиться в регистре, а не в памяти, если это приводит к повышению производительности.)
В настоящее время почти все компиляторы достаточно сложны, чтобы выполнять собственное распределение лучше, чем программист, поэтому использование register
почти всегда бессмысленно.
Ответ 8
Это только образованное предположение, но я сомневаюсь, что вы можете взять адрес регистра на С++, потому что такого мышления просто не существует. С++, вероятно, не использует регистр в вашем конкретном случае. Обратите внимание, что квалификатор класса хранения register
является лишь подсказкой для компилятора (и большинство, если не все современные компиляторы с удовольствием игнорируют его полностью).