Вопрос

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

Это было полезно?

Решение

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

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

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

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

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

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

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

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

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

Другие советы

Параграф 8.5.6 стандарта C++ гласит:

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

(В стандарте также указано, что инициализация локальных переменных не определена)

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

Говоря о Java:

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

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

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

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

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

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

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

Н.Б.В C/C++ «статические» переменные означают совсем другое, чем статические переменные в Java!

Я понятия не имею о Java и сомневаюсь, что для статики/локалов в Java все по-другому.

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

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

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

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

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

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

Это всего лишь предположение, но, возможно, именно так и происходит со статикой, поскольку ее легко реализовать и она полезна.

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

static unsigned char megabyte[1 << 20];

и исполняемый файл не вырастет ни на мегабайт.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top