Вопрос

В C мы не можем использовать &, чтобы узнать адрес регистровой переменной, но в C++ мы можем сделать то же самое.Почему это разрешено в C++, но не в C?Может кто-нибудь объяснить эту концепцию подробно.

Это было полезно?

Решение

Вот выдержка из раздела 6.7.1 (сноска 101) Стандарт C99 (pdf):

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

А из п. 7.1.1 п. 3 п. Стандарт C++ (pdf):

А register спецификатор имеет ту же семантику, что и auto спецификатор вместе с намеком реализации на то, что объявленный таким образом объект будет интенсивно использоваться. [Примечание:подсказку можно игнорировать, и в большинстве реализаций она будет игнорироваться, если будет взят адрес объекта.— конечная заметка]

Забавные подробности о register

Группа C++ (WG21) хочет осудить register:

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

Заметки с встречи в марте 2009 г.:

Консенсус CWG был в пользу отказа от register.

Посмотрите, что делает группа C99 (WG14) сказал о register (pdf) на встрече:

Общее соглашение об отказе от «autoключевое слово.Должны ли мы попросить WG21 вернуться к предыдущему использованию «register(без адреса)?Нет, с WG21 это не сработает.

Другие советы

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

С другой стороны, компилятор C++ не иметь игнорировать «регистрацию» только потому, что вы берете адрес переменной.Теоретически компилятор мог бы сохранить его в регистре и дать вам какое-то магическое значение указателя, которое каким-то образом сопоставляется с регистром за кулисами, но это будет большой работой с очень небольшой выгодой, поэтому никакой компилятор (насколько я знаю) делает что-нибудь подобное.

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

Соответствующая часть стандарта C++ — 7.1.1.3:

Спецификатор регистра имеет ту же семантику, что и спецификатор auto, вместе с намеком на реализацию, что объявленный таким образом объект будет интенсивно использоваться.[Примечание:подсказку можно игнорировать, и в большинстве реализаций она будет игнорироваться, если будет взят адрес объекта.— конечная заметка]

Извините за очень поздний ответ.

Проблема в том, что в C register изначально означало хранение значений в регистре, поэтому только int и char можно использовать для этого.Но со временем и особенно со стандартом C++ он расширился до «быстрого доступа», а не «в регистре ЦП».Итак, в C++ массив может быть register type, но мы знаем, что невозможно хранить массивы в регистре ЦП.Следовательно, логически нормально обращаться к регистру C++ (в указанном выше смысле), но это все равно не имеет смысла, если значения на самом деле находятся в регистре ЦП.

Я предполагаю, что это ключевое слово даже не вошло бы в язык, если бы не совместимость с C.Хотя я не могу говорить с каким-либо авторитетом, если это так, мне кажется, что есть практическая причина, чтобы это было законно, помимо простого стандартного положения «компилятор умнее вас»:C++ принимает адреса вещей без разрешения с большей готовностью, чем C.Конкретно:функции-члены и ссылки.

Поскольку функции-члены требуют неявного this параметр, было бы невозможно вызвать их из объявленного объекта register.В C нет ничего, что запрещало бы вам сказать register struct X x;, поэтому такой язык должен быть разрешен в C++ [поскольку C-совместимость — единственная причина, по которой это ключевое слово вообще существует].Но если вы запретите вызов функций-членов, а также получение адресов, это также распространяется на первоначальный вызов конструктора.По сути, это не будет работать с типами, не относящимися к POD.Таким образом, вы получаете один спецификатор класса хранения, который действителен только для небольшого подмножества допустимых типов, тогда как все остальные можно использовать для чего угодно.

Вы также не можете создавать ссылки на такие объекты, хотя технически компилятор не обязан рассматривать ссылки как указатели. register int i; int& x; не обязательно иметь место для двух переменных, но если вы позже это сделаете &x в итоге вы получите указатель на i.Таким образом, первоначальная конструкция должна быть признана незаконной.Хотя это кажется не проблемой, поскольку ссылки в C все равно не существуют, возвращаясь к предыдущему пункту, типы POD, объявленные с помощью register спецификатор больше не может быть скопирован.Конструктор копирования, предоставляемый компилятором, имеет форму X::X(const X&) или X::X(X&) по мере необходимости.

Итак, чтобы поддерживать совместимость с C, им приходится сделать register уникален как спецификатор класса хранения, поскольку он не применяется ко всем типам и изменяет как минимум две разные части стандарта в другом месте [чтобы указать, что вы не можете создать ссылку на переменную, объявленную с помощью register спецификатор и как-то обойти ссылки для копирования POD].Или они могли бы просто сказать: «Можно взять адрес» и позволить составителям решить, следует ли выполнять запросы.Что-то они все равно планировали сделать.

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

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

Важно помнить, что «регистр» — это всего лишь подсказка для компилятора (причем бессмысленная;Я никогда не видел никакого улучшения скорости, и большинство компиляторов, вероятно, просто игнорируют это).C и C++ разрешено игнорировать ваш «совет» и хранить переменную в памяти.Конечно, если вы возьмете адрес переменной, это заставит ее присвоить место в памяти.

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

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

Это всего лишь обоснованное предположение, но я сомневаюсь, что вы можете взять адрес регистра в C++, потому что такого мышления просто не существует.С++, вероятно, не использует регистр в вашем конкретном случае.Обратите внимание, что квалификатор класса хранилища register это всего лишь подсказка для компилятора (и большинство, если не все, современные компиляторы с радостью полностью ее игнорируют).

C и C++ — два разных языка с большим общим подмножеством.Вот почему некоторые вещи между ними различаются.

Хотя я не понимаю вашего вопроса, register является (по крайней мере, в C++) намеком на то, что к переменной можно обращаться чаще, и не более того.В C это означает, что вы не можете взять адрес с & унарный оператор, что имело определенный смысл в то время.На заре C ожидалось, что компилятор может не беспокоиться о выделении памяти для переменной, и поэтому не обязательно будет адрес, который нужно будет взять.

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top