Статическая инициализация переменных?

Я хочу знать, почему именно статические переменные в C, С++ и Java инициализируются нулем по умолчанию? И почему это не так для локальных переменных?

Ответ 1

Почему статические переменные детерминистически инициализируются и локальные переменные не являются?

Посмотрите, как применяются статические переменные. Память для них выделяется во время связи, а начальное значение для них также предоставляется во время соединения. Накладные расходы не работают.

С другой стороны, память для локальных переменных выделяется во время выполнения. Стек должен расти. Вы не знаете, что было раньше. Если вы хотите, вы можете очистить эту память (ноль), но это может привести к чрезмерной нагрузке во время выполнения. Философия С++ - это "вы не платите за то, что не используете", поэтому по умолчанию эта память не равна нулю.

ОК, но почему статические переменные инициализируются нулем, а не какое-то другое значение?

Ну, вы вообще хотите что-то сделать с этой переменной. Но откуда вы узнали, была ли она инициализирована? Вы можете создать статическую логическую переменную. Но тогда он также должен быть надежно инициализирован чем-то (предпочтительно ложным). Как насчет указателя? Вы хотите, чтобы он был инициализирован NULL, чем какой-то случайный мусор. Как насчет структуры/записи? У него есть некоторые другие элементы данных внутри. Имеет смысл инициализировать все из них по умолчанию. Но для простоты, если вы используете стратегию "initialize to 0", вам не нужно проверять отдельные члены и проверять их типы. Вы можете просто инициализировать всю область памяти до 0.

Это не является техническим требованием. Семантику инициализации все равно можно считать нормальным, если значение по умолчанию является чем-то отличным от 0, но все еще детерминированным. Но тогда, какова должна быть эта ценность? Вы можете с легкостью объяснить, почему используется 0 (хотя в действительности это звучит слегка произвольно), но объяснение -1 или 1024 кажется еще сложнее (особенно, что переменная может быть недостаточно большой, чтобы удерживать это значение и т.д.).

И вы всегда можете инициализировать переменную явно.

И у вас всегда есть параграф 8.5.6 стандарта С++, в котором говорится: "Каждый объект статической продолжительности хранения должен быть инициализирован нулем при запуске программы".

Для получения дополнительной информации, пожалуйста, обратитесь к этим другим вопросам:

Ответ 2

В пункте 8.5.6 стандарта С++ указано, что:

"Каждый объект статической продолжительности хранения должен быть инициализирован нулем при запуске программы"

(Стандарт также говорит, что инициализация локальных переменных undefined)

Что касается того, почему стандарт не говорит;) Можно догадаться, что его достаточно легко реализовать без каких-либо дополнительных недостатков.

Ответ 3

Говоря о java:

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

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

Переменные с собственным типом не могут получить значение null, поэтому нелокальные переменные инициализируются с помощью 0 или false в качестве резервной копии. Это не лучшее решение, конечно, но я не знаю лучшего.; -)

Ответ 4

В какой-то степени это всего лишь дизайнерские решения со стороны разработчиков языка. Но вероятными причинами этих решений на Java являются:

  • для статических/переменных-членов, если вы собираетесь их инициализировать чем-то, то нуль является удобным значением, потому что (a) обычно это подходящее значение означает "не настроено на что-то особенное" и является значением вы бы выбрали в любом случае, например, счетчики; и (б) внутренне, вероятно, что нуль может использоваться для "специальных" значений, особенно для представления null в случае ссылки на объект.
  • для локальных переменных, не предоставляя им значение по умолчанию, позволяет правило, которое заставляет программиста устанавливать некоторое значение перед чтением переменной, что может быть действительно полезно, если компилятор обнаруживает определенные ошибки.

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

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

N.B. В C/С++ "статические" переменные означают другую вещь для статических переменных в Java!

Ответ 5

Я понятия не имею о java, и я сомневаюсь, что это отличается от статики/локальных жителей в java.

Что касается c и С++, то это касается программистов, которые заботятся о своем кодовом эффекте и любят находиться под контролем. Инициализация локальных переменных будет означать выполнение дополнительного кода каждый раз, когда программа входит в область. Для часто называемых функций, которые могут быть катастрофой.

Ответ 6

Это связано с концепцией "только платить за то, что вы используете" в C/С++.

Для статических переменных инициализация может быть выполнена без генерации кода. Объектный файл содержит начальные значения для переменных в сегменте данных и когда ОС загружает загружаемый исполняемый файл и отображает этот сегмент данных до запуска программы.

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

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

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

Ответ 7

Это всего лишь предположение, но это может быть так, как для статики, поскольку оно легко реализовать и полезно.

Компилятор может совместно распределять все переменные в одну область смежных областей памяти, а затем либо испускать код (один вызов memset()), чтобы очистить его до вызова main(). Во многих случаях он также может полагаться на функции исполняемого файла операционной системы, если этот формат поддерживает " bss sections" , которые очищаются вместо этого загрузчик. Это экономит место в исполняемом файле, вы можете иметь

static unsigned char megabyte[1 << 20];

и исполняемый файл не будет увеличиваться на мегабайт.

Для локальных переменных ни одно из них не применяется; они распределяются "на лету" (как правило, в стеке), и это будет пустой тратой ресурсов, чтобы очистить их, поскольку они обычно будут назначены очень скоро в любом случае.