Страницы

Поиск по вопросам

среда, 5 февраля 2020 г.

Выделение памяти под неинициализированные переменные

#c #память


Подскажите пожалуйста, выделяется ли память под переменные если они просто объявлены,
но им не присвоены конкретные значения. Например, написал просто int x,y,z и при этом
их не использовал никак по ходу программы.
    


Ответы

Ответ 1



Если не использовали вообще - то умный оптимизатор их выбросит, не выделив память. Если вы использовали x для чтения без предварительной записи, а перед этим просто написали int x; не в глобальной области видимости - место будет выделено, но не инициализировано, о чем умный компилятор должен бы предупредить - об использовании неинициализированной переменной. Кусочек из книжки "С. Справочник. Полное описание языка": Объявление объекта является определением, если оно выделяет память для объекта. Объявления, которые включают инициализаторы, всегда являются определениями. Кроме того, все объявления в блоке функции являются определениями, если только они не содержат спецификатор класса памяти extern. Вот несколько примеров: int a = 10; // Определение a. extern double b[]; // Объявление массива b, определенного // в другом месте программы. void func() { extern char c; // Объявление, но не определение c. static short d; // Определение d. float e; // Определение e. /* ... */ } Если вы объявляете объект за пределами всех функций, без инициализатора и без спецификатора памяти extern, такое объявление является предполагаемым определением (tentative definition). Вот несколько примеров: int i, v[]; // Предполагаемые определения i, v и j. static int j; Предполагаемое определение идентификатора остается простым объявлением, если единица трансляции содержит еще одно определение того же самого идентификатора. Если же нет, то компилятор ведет себя так, как будто предполагаемое определение включает инициализатор с нулевым значением, что делает его определением. Таким образом, переменные i и j типа int в предыдущем примере, идентификаторы которых объявляются без инициализаторов, неявно инициализируются значением 0, а массив v с типом элементов int имеет один элемент с исходным значением 0.

Ответ 2



Вы неявно предполагаете, что компилятор честно выделяет память под каждую переменную в отдельности. Это уже давно не так. Современные оптимизаторы могут поместить любую переменную в регистры, в общую область памяти с другой переменной, если их время жизни не пересекается, или вовсе преобразовать код и исключить переменную. Поэтому не имеет смысла экономить на переменных, компилятор всё сделает правильно и экономно. Пример: вот такой код int f() { int x = 5, y = 8; x += y; y = 7 * x; return x + y; } intel compiler 17 компилирует в push 104 pop rax ret а gcc 6.3 в mov eax, 104 ret Вы видите, что компилятор выкинул вообще все переменные и вычисления.

Ответ 3



Например, такой код завершается аварийно (MinGW) int main() { double v[1000000]; return 0; } В данном случае видимо выделяется. По ходу переполнение стека.

Комментариев нет:

Отправить комментарий