Статическая переменная инициализация? - PullRequest
10 голосов
/ 02 декабря 2009

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

Ответы [ 7 ]

20 голосов
/ 02 декабря 2009

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

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

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

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

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

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

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

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

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

4 голосов
/ 02 декабря 2009

В пункте 8.5.6 стандарта C ++ говорится, что:

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

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

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

3 голосов
/ 02 декабря 2009

Выступая за Java:

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

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

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

2 голосов
/ 02 декабря 2009

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

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

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

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

N.B. В C / C ++ «статические» переменные означают нечто иное, чем статические переменные в Java!

1 голос
/ 02 декабря 2009

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

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

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

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

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

1 голос
/ 02 декабря 2009

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

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

0 голосов
/ 02 декабря 2009

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

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

static unsigned char megabyte[1 << 20];

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

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

...