встроенная сборка — Как хранить переменную 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;
}

12

Решение

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

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

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

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

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

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

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

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

28

Другие решения

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

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

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

6

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

3

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

Используйте правильный уровень оптимизации, например. -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
3

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

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

1

Обычно компиляторы 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

Строка ‘volatile register 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
1

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

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

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

0

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

0
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector