Адрес переменной регистра - PullRequest
15 голосов
/ 10 августа 2009

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

Ответы [ 8 ]

31 голосов
/ 10 августа 2009

Вот выдержка из Раздела 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.

5 голосов
/ 28 апреля 2011

Извините за супер поздний ответ.

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

5 голосов
/ 10 августа 2009

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

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

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

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

.

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

3 голосов
/ 28 апреля 2011

Я предполагаю, что ключевое слово даже не попало бы в язык, если бы не совместимость с Си. Хотя я не могу говорить с какими-либо полномочиями, если это так, мне кажется, есть практическая причина, по которой он должен быть легальным, за исключением простого применения стандарта «компилятор умнее вас»: 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]. Или они могут просто сказать «все в порядке, чтобы взять адрес» и позволить компиляторам решать, удовлетворять запросы или нет. Что-то, что они планировали делать так или иначе.

1 голос
/ 10 августа 2009

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

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

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

1 голос
/ 10 августа 2009

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

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

0 голосов
/ 10 августа 2009

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

0 голосов
/ 10 августа 2009

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

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

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

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

...