Адрес переменной, хранящейся в регистре

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

В противном случае, что произойдет, если я попрошу адрес такой переменной (сохраненной как регистр)? Я знаю, что мы не можем принять адрес переменных, явно установленных для регистрации (register int c).

EDIT:

Например, если я делаю что-то вроде

int c = 1;
print("Address of c: %p", &c);

Затем эту переменную не удалось сохранить в регистре, не так ли? Компилятор автоматически установит его как сохраненный в памяти? В противном случае (если он просто хранится в регистре), каким будет адрес, отображаемый на экране?

Ответ 1

Во-первых, C-стандарт запрещает принимать адрес переменной, объявленной register, так же, как и для битных полей в struct s.

Для нерегистрационных ( "авто" ) переменных короткий ответ - да. Простейшей стратегией оптимизатора является немедленное разлитие переменных, адреса которых приняты.

"Проливание" - это всего лишь термин из литературы распределения регистров, означающий "решить разместить в памяти, а не в регистре".

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

Другая соответствующая оптимизация - это разделение живого диапазона. Это позволяет хранить переменную в регистре для части диапазона инструкций, где она содержит полезное значение (его "диапазон действия" ) и разливается в других частях. В этом случае разлитые части будут соответствовать местам, где указатель может использоваться для изменения значения переменной. Например:

x = 3;
... lots of computations involving x
if T {
  // SPILL HERE, so store register holding x to memory
  int *p = &x;
  ... lots of computations, perhaps using p to change x
  *p = 2;
  // DONE SPILL HERE, so reload register
  ... more code here not using p to change x.
}
else {
  ... lots of computations involving x.
}

Агрессивный оптимизатор этого кода может выделять позицию стека для x, но загружать его в регистр вверху кода, поддерживая его там, кроме региона, отмеченного как SPILL. Эта область будет окружена хранилищем регистра в память и соответствующей загрузкой регистра.

Ответ 2

Принимая его адрес, вы вынуждаете компилятор помещать переменную в память и не оптимизировать ее в регистр.

В этом ответе есть хорошая информация: Адрес переменной регистра

Ответ 3

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