Немного смущенно о функциях constexpr

Рассмотрим следующий код:

constexpr const int* address(const int& r)
{
   return &r;
}


int main()
{
   int x = 10;
   constexpr const int* p = address(x); //error

   _getch();
   return 0;
}

Это ошибка: "вызов функции должен иметь постоянное значение в постоянном выражении". Хорошо.

Два вопроса:

  • Если 'x' объявлен static, ошибок нет. Почему?

  • Как можно получить адрес переменной во время процесса компиляции? Не распределяются ли они во время выполнения?

Ответ 1

Если "x" объявлено статическим, ошибок нет. Почему?

Это потому, что в программе всегда есть ровно один x. Он имеет адрес (где-то в сегменте .data в нормальных условиях).

Смутно, что ключевые слова static и extern определяют длительность хранения как статическую (они различаются в зависимости)

Как можно получить адрес переменной во время процесса компиляции? Не распределяются ли они во время выполнения?

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

Ответ 2

Указатель на переменную с длительностью хранения static - constexpr. Вы можете увидеть это в следующей программе:

int main() {
    static int x;
    int y;
    constexpr int* px = &x; // Compilation is successful
    constexpr int* py = &y; // Compilation will fail
}

См. https://ideone.com/lc9u3E

px - это выражение константы адреса. Здесь стандартная ссылка:

[5.19p3]:

Выражение константы адреса является выражением константы основного значения prvalue типа указателя, который оценивает адрес объекта со статическим время хранения, адрес функции или нулевой указатель значение или константное выражение константы prvalue типа std:: nullptr_t.

Ответ 3

Адрес переменной со статической продолжительностью хранения неизвестен во время компиляции. Он известен только во время соединения. Указатель на переменную со статической продолжительностью хранения может использоваться во время компиляции, потому что точное значение адреса не имеет значения - сравнения во время компиляции во время компиляции не допускаются.

Ответ 4

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

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

Ответ 5

К вопросу 2: "Как можно получить адрес переменной во время процесса компиляции? Не распределены ли они во время выполнения?"

x помещается в стек, и при изменении стека он имеет другой адрес. Это может случиться, если x не объявлен в main(), а в некоторой другой функции, которая вызывается из разных мест. Например, попробуйте

#include <iostream>
constexpr const int* address(const int& r)
{
   return &r;
}


int f()
{
   int x = 10;

   const int* p = address(x);
   std::cout << "p=" << p << std::endl;
}

int g()
{
    int data[1000];
    f();
}

main()
{
   f();
   g();
   return 0;
}