Как сохранить переменную C++ в регистре

Я хотел бы получить некоторые пояснения относительно хранения регистровых переменных: есть ли способ гарантировать, что если мы объявили регистровую переменную в нашем коде, она будет храниться ТОЛЬКО в регистре?

#include<iostream>

using namespace std;

int main()
{
    register int i = 10;// how can we ensure this will store in register only.
    i++;
    cout << i << endl;
    return 0;
}

person ashutosh kumar    schedule 09.04.2013    source источник
comment
C и C++ не гарантируют, что аппаратное обеспечение, на котором работает программа, даже имеет регистры. Это просто подсказка компилятору.   -  person Stephen Canon    schedule 09.04.2013
comment
@StephenCanon Не просто подсказка в C, объявление переменной register запрещает использование ее адреса там. (Это не более чем подсказка относительно помещения переменной в регистр.)   -  person Daniel Fischer    schedule 09.04.2013
comment
это поможет вам: Stack Overflow, как узнать, где хранится ли регистровая переменная? не ваш ответ, но вы можете найти интересным   -  person Grijesh Chauhan    schedule 09.04.2013
comment
в дополнение к комментарию «почему вас это волнует». Мы могли бы сказать, что компилятор всегда будет хранить переменную в регистре - что теперь? Мы могли бы сказать, что все простые локальные переменные всегда хранятся в регистре — что теперь. У него нет логического смысла, если только он не имеет видимого/полезного побочного эффекта. Например, «розовый int i = 2;» запрос на сохранение переменной в розовой памяти   -  person pm100    schedule 10.04.2013


Ответы (8)


Вы не можете. Это только подсказка компилятору, которая предполагает, что переменная интенсивно используется. Вот формулировка C99:

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

А вот формулировка С++ 11:

Спецификатор register указывает реализации, что объявленная таким образом переменная будет интенсивно использоваться. [Примечание: подсказку можно игнорировать, и в большинстве реализаций она будет проигнорирована, если будет взят адрес переменной. Это использование устарело (см. D.2). -конец примечания]

Фактически, спецификатор класса хранения register устарел в C++11 (Приложение D.2):

Использование ключевого слова register в качестве описателя класса хранения (7.1.1) не рекомендуется.

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

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

person Joseph Mansfield    schedule 09.04.2013
comment
Меня всегда удивляло, что код помечает каждую локальную переменную знаком register. - person Pete Becker; 09.04.2013
comment
@PeteBecker Кому нужна оперативная память? Я весь в регистрах! - person Joseph Mansfield; 09.04.2013
comment
ваша аргументация только C++. C накладывает ограничения на регистровые переменные. - person Jens Gustedt; 10.04.2013
comment
@JensGustedt Это все еще только намек на C. Я заметил, когда говорил конкретно о C ++. Я немного конкретизировал ответ. - person Joseph Mansfield; 10.04.2013
comment
Ах, хочется тосковать по дням, когда можно было закодировать register(4), а переменная оказалась бы в регистре 4. (Затем вы бы выполнили несколько вызовов процедур gen, чтобы выполнить сборку.) - person Hot Licks; 10.04.2013
comment
@sftrabbit, no in - это не только подсказка в C. В C получение адреса переменной register является нарушением ограничения. Это реальная семантическая разница. Программы, которые компилируются для C++, не будут компилироваться для C. - person Jens Gustedt; 10.04.2013

Ключевое слово register имеет разные значения в C и C++. В C++ это на самом деле избыточно и кажется даже устаревшим в наши дни.

В Си по-другому. Во-первых, не воспринимайте название ключевого слова буквально, оно не всегда связано с «аппаратным регистром» на современном процессоре. Ограничение, которое наложено на переменные register, заключается в том, что нельзя взять их адрес, операция & не разрешена. Это позволяет пометить переменную для оптимизации и гарантировать, что компилятор будет кричать на вас, если вы попытаетесь взять ее адрес. В частности, переменная register, которая также имеет квалификацию const, никогда не может быть псевдонимом, поэтому она является хорошим кандидатом для оптимизации.

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

person Jens Gustedt    schedule 09.04.2013
comment
Я думаю, вы имели в виду буквально (или дословно) вместо подробного в первом предложении второго абзаца. - person Jeff Hammond; 26.06.2013

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

Используйте правильный уровень оптимизации, например. -O2

Держите количество переменных небольшим

register int a,b,c,d,e,f,g,h,i, ... z;  // can also produce an error
// results in _spilling_ a register to stack
// as the CPU runs out of physical registers

Не берите адрес регистровой переменной.

register int a;
int *b = &a;  /* this would be an error in most compilers, but
                 especially in the embedded world the compilers
                 release the restrictions */

В некоторых компиляторах можно предложить

register int a asm ("eax");  // to put a variable to a specific register
person Aki Suihkonen    schedule 09.04.2013
comment
ваша аргументация только C++. C накладывает ограничения на register переменных. Также ваш пример из gcc о asm вводит в заблуждение. Для gcc это не предложение. Если вы укажете регистр, этот регистр должен существовать и будет использоваться. - person Jens Gustedt; 10.04.2013
comment
документы GCC обновлены: register ... asm() local< /i> переменные больше не гарантируют ничего, кроме выбора этого регистра для ограничения "r". На практике GCC по-прежнему использует указанные регистры; clang не выходит за пределы операторов asm. Связано: Чтение значения регистра в переменную C - person Peter Cordes; 17.11.2019

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

person NPE    schedule 09.04.2013
comment
ваша аргументация только C++. C накладывает ограничения на регистровые переменные. - person Jens Gustedt; 10.04.2013

Ключевое слово «register» — это пережиток того времени, когда компиляторы должны были устанавливаться на машинах с 2 МБ ОЗУ (совместно используемыми между 18 терминалами, на каждом из которых входил пользователь). Или ПК/домашние компьютеры с 128-256 КБ ОЗУ. В этот момент компилятор действительно не мог выполнить большую функцию, чтобы выяснить, какой регистр использовать для какой переменной, чтобы использовать регистры наиболее эффективно. Поэтому, если программист дал «подсказку» с помощью register, компилятор поместил бы это в регистр (если это возможно).

Современные компиляторы не умещаются несколько раз в 2 МБ ОЗУ, но они намного умнее присваивают переменные регистрам. В приведенном примере я нахожу очень маловероятным, что компилятор не поместил бы его в регистр. Очевидно, что число регистров ограничено, и при достаточно сложном фрагменте кода некоторые переменные не помещаются в регистры. Но для такого простого примера современный компилятор сделает i регистром, и он, вероятно, не будет трогать память до тех пор, пока где-нибудь внутри ostream& ostream::operator<<(ostream& os, int x).

person Mats Petersson    schedule 09.04.2013
comment
хаха, 18 терминалов по 2Мб. убирайся с моей лужайки :-) CP-67 поддерживал 60 пользователей наполовину меньше. - person jthill; 10.04.2013
comment
Да, моя школа разделяла 2MB PDP-11 с RSTS-E, и у него было 8 терминалов и один принтер в моей школе, 8+1 в соседней школе, а затем в основной школе было две комнаты с 16 терминалами в каждой комнате ( плюс несколько случайных терминалов, разбросанных в нескольких других местах). Для этого существовал компилятор C, но большинство из нас использовали современный в то время язык Pascal. - person Mats Petersson; 10.04.2013

Единственный способ убедиться, что вы используете регистр, — использовать встроенную сборку. Но даже если вы это сделаете, вам не гарантируется, что компилятор не сохранит ваше значение вне блока встроенного ассемблера. И, конечно же, ваша ОС может решить прервать вашу программу в любой момент, сохранив все ваши регистры в памяти, чтобы передать ЦП другому процессу.

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

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

person cmaster - reinstate monica    schedule 12.02.2014

Как правило, компиляторы CPP (g++) вносят немало оптимизаций в код. Поэтому, когда вы объявляете регистровую переменную, компилятору не обязательно сохранять это значение непосредственно в регистре. (т. е.) код «register int x» может не привести к тому, что компилятор сохранит этот int непосредственно в регистре. Но если мы сможем заставить компилятор сделать это, мы можем добиться успеха.

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

int main() {
    volatile register int x asm ("eax"); 
    int y = *(&x);
    return 0;
}

Для меня компилятор g++ в этом случае выдает следующую ошибку.

[nsidde@nsidde-lnx cpp]$ g++ register_vars.cpp 
register_vars.cpp: In function ‘int main()’:
register_vars.cpp:3: error: address of explicit register variable ‘x’ requested

Строка «изменчивый регистр int x asm («eax»)» указывает компилятору хранить целое число x в регистре «eax» и при этом не выполнять никаких оптимизаций. Это гарантирует, что значение будет сохранено непосредственно в регистре. Вот почему обращение к адресу переменной вызывает ошибку.

Кроме того, компилятор C (gcc) может выдать ошибку со следующим кодом.

int main() {
    register int a=10;
    int c = *(&a);
    return 0;
}

Для меня компилятор gcc в этом случае выдает следующую ошибку.

[nsidde@nsidde-lnx cpp]$ gcc register.c 
register.c: In function ‘main’:
register.c:5: error: address of register variable ‘a’ requested
person Nagakishore Sidde    schedule 04.08.2014
comment
Этот синтаксис asm("eax") — именно то, что я искал. спасибо за реальный ответ на вопрос - person benathon; 01.02.2018
comment
Он не ссылался на документы для такого использования asm, который содержит полезную информацию. В частности: Единственное поддерживаемое использование этой функции — указание регистров для входных и выходных операндов при вызове расширенного ассемблера. Таким образом, нет никакой гарантии, что какое-либо конкретное значение будет находиться в eax в любой конкретный момент времени, если только/ пока вы не вызовете расширенный asm. Что возвращает нас к тому, что говорят все остальные: на самом деле это больше не имеет большого значения. - person David Wohlferd; 19.05.2020

Здесь вы можете использовать volatile register int i = 10 в C++, чтобы обеспечить сохранение i в регистре. Ключевое слово volatile не позволит компилятору оптимизировать переменную i.

person sree    schedule 06.04.2014
comment
Даже не близко. Volatile заставляет компилятор предположить, что любой доступ к переменной имеет видимые побочные эффекты, и они принудительно не изменяются из-за оптимизации. Это означает, что он просто не может изменить порядок операторов с видимыми побочными эффектами. - person ABaumstumpf; 26.08.2020