1

Слот памяти объемом 4 байта зарезервирован для каждого определенного целого. Неинициализированная переменная поддерживает старое значение этого слота. следовательно, начальное значение каким-то образом рандомизировано.Начальные значения целых чисел C++ Global и Scoped

int x = 5; // definition with initialisation 

Этот факт в большинстве компиляторов C++, насколько мне известно, относится к облачным переменным. Но, когда дело доходит до глобальных переменных. будет установлено значение нуля.

int x; // uninitialised definition 

Почему компилятор C++ ведет себя по-разному относительно начального значения глобальных и скопированных переменных.

Является ли это фундаментальным?

ответ

4

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

§ 3.6.2/2 от стандарта C++ (n3242) говорит,

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

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

+0

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

+0

Представьте, сколько меньше ошибок в коде C/C++ в мире, если по умолчанию было инициализировать все переменные до нуля. Так как локальный «int x;», x гарантированно равен нулю. Если вам действительно нужна производительность, вы можете написать что-то вроде «uninitialized int x;» – joeking

+0

@ joeking: Когда есть несколько вариантов, C и C++ выбрали (и по-прежнему выбирают) тот, который более эффективен. Local: 'int x [10000];' все элементы x равно * uninitialized * по умолчанию (по причине производительности); если вам действительно нужно, чтобы они были нулевыми инициализированными, напишите: 'int i [10000] = {0};' теперь все элементы гарантированно равны нулю. :-) – Nawaz

1

Как и следовало ожидать, для этого поведения также существуют причины, основанные на эффективности.

Пространство в стеке обычно выделяется просто путем корректировки указателя стека. Если у вас есть 32 байта простых переменных в функции, тогда компилятор испускает команду, эквивалентную «sp = sp - 32» Любая инициализация этих переменных потребует дополнительного кода и времени выполнения - следовательно, они в конечном итоге инициализируются, по-видимому, случайными значения.

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

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

C++ также позволяет глобальным переменным, которые требуют выполнения кода для инициализации, C не позволяет этого. Например, "int x = rand();" Инициализируется во время выполнения кодом в исполняемом файле.

Попробуйте добавить эту глобальную переменную int x [1024 * 1024]; и посмотреть, не имеет ли значение размер исполняемого файла. Теперь попробуйте: int x [1024 * 1024] = {1,2,3}; И посмотрите, какая разница.

+0

На самом деле, если у вас есть 32 байта простых переменных в функции, компилятор зарезервирует некоторое количество байтов, которые касаются только касательно 32. Например, обратный адрес часто требует 4 дополнительных байта, регистры должны быть сохранены, а временные требуется пространство стека. С другой стороны, не все пользователи пространства стека делают это одновременно, а некоторые объекты могут совместно использовать одно и то же пространство стека в разное время. – MSalters

+0

Ну конечно, но для понимания основ здесь вам не нужно беспокоиться о таких деталях. Большинство компиляторов при генерации кода режима отладки предоставят каждой локальной переменной уникальный слот в стеке (в дополнение к небольшому количеству накладных расходов для других вещей) - выделены в одном блоке. – joeking

2

«Слот памяти объемом 4 байта зарезервирован для каждого определенного целого»..

Нет, это не так. Невзирая на размер «4 байта», основная проблема с этим утверждением заключается в том, что современные компиляторы часто находят новое местоположение для переменной каждый раз, когда она назначена. Это может быть регистр или какое-то место в памяти. В этом есть много сообразительности.

Неинициализированная переменная не записывается, поэтому в целом нет даже места, предназначенного для нее. Попытка прочитать «это» может вообще не давать значения; компилятор может выйти из строя, чтобы сгенерировать для этого код.

Теперь глобалы - это другое дело. Поскольку они могут быть прочитаны и записаны в любом месте, компилятор не может просто найти новые места для них при каждой записи. Они обязательно должны придерживаться одного места, и он не может быть реалистичным регистром. Часто они все распределяются вместе в одном куске памяти. Обнуление этого фрагмента обычно выполняется очень эффективно. поэтому глобальные перемены разные.

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