@LamerFromSpace
Студент-быдлокодер

Как происходит создание переменных в Си?

Читаю книгу The C Programming Language, вижу такое предложение:

5cbcd364a4869119321288.png

Хочу потыкать это в коде, получаю в отладчике следующее:

5cbcd410f0da1496715533.png
В переменной не мусор. Во что верить?

Компилю по стандарту С99
  • Вопрос задан
  • 138 просмотров
Решения вопроса 2
dollar
@dollar
uBlock, Ghostery, WOT, TosterComfort, RKN Alert
По классике локальные переменные создаются на стеке. То есть там же, куда кладутся параметры функции. А после выхода из функции указатель стека возвращается на прежнее место, как бы освобождая память. Но это не настоящее выделение памяти, то есть она выделяется не из кучи, а гораздо быстрее. И также быстро освобождается.

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

Всякую там оптимизацию и отладочную информацию обычно можно настраивать.
Ответ написан
@res2001
Developer, ex-admin
Немного усложните программу, например написав парочку функций, которые определяют еще несколько переменных и что-нибудь в них пишут. В main() вызовите эти функции, а затем объявите test и выведите его значение. Вот тогда у вас гарантированно образуется мусор. При компиляции, нужно еще предотвратить оптимизацию компилятором (опция -O0), а то он может выкинуть вызовы функций, если посчитает, что они не влияют на дальнейшее выполнение программы.

Что бы понять происходящее, почитайте как работает стек.
Автоматические переменные определяются на стеке. Одно и то же место на стеке в разное время выполнения программы могут занимать разные переменные. Если вы не инициализируете автоматическую переменную, то она принимет то значение, которое уже лежит в области памяти, которую она занимает. Из-за того, что переменные имеют разный размер, то часто, например текущая 4 байтовая переменная (int) может занимать память, в которой до этого были 2 двух байтовые переменные, или любые другие вариации.
Стек выделяется при загрузке программы (или при старте потока). В ходе выполнения программы стек не освобождается и не перевыделяется, поэтому мусор (данные от старых автоматических переменных) в нем образуется постоянно. При выходе автоматической переменной из области видимости фактического освобождения памяти не происходит - просто изменяется указатель на стек (регистр sp), т.е. при этом не происходит даже обращения к памяти. Поэтому все ранее сохраненные в стеке значения в памяти остаются. И когда вы определяете новую переменную без инициализации, она занимает ранее освобожденное место и принимает какое-то значение (мусор), которое ранее было сохранено в эту область памяти.
Ответ написан
Пригласить эксперта
Ответы на вопрос 3
Zoominger
@Zoominger
Сись админ
Это от компилятора зависит и от места переменной в памяти (что в ней до этого было), иногда 0, иногда магические числа.
Ответ написан
@vanyamba-electronics
Читаю написанное:

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


Локальные переменные в функциях создаются выделением памяти на стеке. Например:
[SP+4] // int text;
При этом вершина стека просто сдвигается вниз:
SP = SP - 4;
Что там находится при этом, никого не интересует - что-то да находится. Поэтому такое значение можно считать мусором.
Отладчик обычно пишет, что там ноль. Но отладочная сборка отличается от релизной, и там может быть что угодно.
Ответ написан
CityCat4
@CityCat4
Кошки не похожи на людей, кошки - это кошки!
Переменные, не обьявленные статическими, создаются в динамической области памяти ("куче") и будут иметь случайное значение. То, что там сейчас нуль - это вовсе не значит, что всегда и везде там будет нуль. Полагаться на то, что переменная после обьявления содержит (не содержит) какое-то значение - верный путь огрести SIGSEGV и самая распространенная ошибка.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы