2012-01-14 2 views
6

Я читаю книгу, в которой упоминается этотРаспределения памяти для константных переменных

Если компилятор знает каждое использование сопзЬ, нет необходимости выделять пространства для хранения его. Например:

  1. const int c1=1;
  2. const int c3=my_f(3);
  3. extern const int c4;

Учитывая, что значения с3 и с4 не известны, как время компиляции, хранения должны быть выделены для с3 и с4.

Я ничего не понял. Мои сомнения:

Что это значит, удерживая здесь? Разве не нужно было хранить все в памяти? Для c1, не будет ли у нас распределения памяти?

Прошу прояснить мои сомнения.

спасибо.

+1

Что случилось с 'c2'? –

ответ

4

c1 отличается от двух других констант тем, что он инициализируется литеральным значением . Это позволяет компилятору поместить это значение везде константа используется, например:

int x = z + c1; 

можно заменить

int x = z + 1; 

Это означает, что компилятор не нужно выделять место и хранить 1 в нем.

c3 и c4 разные: один рассчитывается с использованием функции, а другой - из другого блока компиляции. Это означает, что компилятор больше не может выполнять подстановку так, как мог, с c1: значения c3 и c4 не известны компилятору. Поэтому компилятор генерирует код для

int x = z + c4; 

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

+0

Благодарим за ответ, но это означает, что всякий раз, когда переменная определяется как const и инициализируется литералом, она действует как макрос, и везде, где в программе используется, компилятор просто заменяет переменную значением? –

+1

@Leoheart Компилятор * разрешен * для этой замены, и большинство компиляторов делают это. Но, насколько мне известно, компиляторам не нужны «встроенные» объявленные константы: стандарт позволяет им делать в любом случае.Кроме того, вам разрешено указывать адрес объявленной константы, и в этом случае компилятор помещает его в память в дополнение к его вставке в тех местах, где он используется. – dasblinkenlight

+0

Получил. Благодарю. –

1

Как интегральное выражение константы, компилятор имеет полное право использовать постоянную фальцовку, чтобы удалить ее из программы. Это неверно, если вы берете его адрес. Кроме того, современный оптимизирующий компилятор может использовать LTO, inlining и постоянную фальцовку, чтобы сделать то же самое с c3 и c4, если это возможно.

Если вы не берете адрес переменной, компилятор не обязан выделять его, если он может генерировать код с эквивалентными результатами в соответствии с правилом as-if.

Редактировать: Постоянное свертывание - это то, где компилятор вычисляет выражения во время компиляции, а не во время выполнения. Например, вы можете законно делать int x[3 + 4];, где 3 + 4 оценивается во время компиляции. Некоторые примеры, особенно те, которые связаны с МКО, стандартизированы, но реализация может выполнять больше, если это возможно. LTO - это оптимизация времени связи, когда компилятор выполняет оптимизацию между единицами перевода, когда они связаны друг с другом.

Это означает, что компилятор может вставлять тело my_f, а затем (в зависимости от тела) константу складывать, чтобы сделать c3 постоянным выражением, а затем постоянно складывать его туда, где он используется, и не выделять его. Для c4 LTO может давать значение c4 в качестве постоянного выражения, и в этом случае он может быть также сложен и удален.

В C++ 11 есть функции constexpr, которые позволяют сделать еще многое в этой области.

+0

Извините, я тоже не могу понять ваш ответ. что такое постоянное складывание и LTO? –

+0

Получил это. Благодарю. –

+0

Последний вопрос: означает ли это когда переменная, определенная как константа и инициализируемая литералом, действует как макрос, а где-то в программе используется компилятор Justs заменяет переменную на значение? –

2

У Const есть 2 цели использования - замена макросов (константных выражений), а также неизменяемых данных.

Это утверждение:

const int c1=1; 

Есть по существу типобезопасный версия этого:

#define c1 1 

Такой, что этот код:

int foo = c1; 

Может просто быть скомпилирован как:

int foo = 1; 

Какая эффективность.

С другой стороны, это:

const int c3=my_f(3); 

используется в качестве непреложного c3. Вероятно, он существует в памяти, но вы не можете его изменить. Это, по сути, более безопасная версия int c3=my_f(3);.

Для иллюстрации:

int a1[c1]; 
int a2[c3]; 

a1 справедливо, так как компилятор может вывести a1 быть постоянным выражением. a2 не является, поскольку в то время как c3 является const, он не может быть известен во время компиляции.

C++ 11 добавляет ключевое слово constexpr, которое аналогично const, хотя оно более строгое, чем const. Только c1 и c2 может быть constexpr. c3 также может быть, хотя для этого потребуется my_f.

Смежные вопросы