Например, когда я определяю переменную, например int x = 20;
, в функции, которую можно вызвать в основной функции, выделяет ли компилятор уже стековую память для этой переменной? Потому что, как я уже сказал, это переменная, которую можно вызывать, но можно и не вызывать, и программа может завершиться и никогда не вызвать ее.
Я изучаю динамическое распределение памяти и варианты использования malloc, и я читал кое-что, что привело меня в полное замешательство, лол.
Стандарт C позволяет компиляторам делать все, что программа не может обнаружить. Поскольку функция никогда не вызывается, вы не можете обнаружить существование ее переменных, поэтому компилятору разрешено (но не обязательно) полностью удалить ее.
Память, необходимая для x
, помещается в стек каждый раз, когда вызывается функция (или, конечно, 0 раз, если функция никогда не вызывается). Это происходит во время выполнения, компилятор не резервирует/предварительно выделяет память. Если окажется, что у вас недостаточно памяти, вы получите переполнение стека или ошибку нехватки памяти.
Люди могут дать вам ответы и объяснения, но, честно говоря, я думаю, что единственный способ добиться реальной ясности в том, как это работает, — это пойти и немного изучить ассемблер.
Вы знаете о рекурсии? Когда вы вызываете функцию foo
изнутри foo
, как бы вы предварительно выделили память для каждого вложенного вызова этой функции? Вам нужен отдельный int x
для каждого из вложенных вызовов.
Если вы на самом деле не присвоите другое значение x
внутри своей функции, то компилятор имеет право просто загружать это постоянное значение 20 всякий раз, когда x
используется. Даже если вы измените значение x
, оптимизатор все равно может сохранить переменную в регистре и никогда не записывать ее в память. Обычно это происходит с часто используемыми переменными цикла и несколькими часто используемыми переменными. Такие агрессивные функции оптимизации обычно отключаются в режимах отладки, где все переменные явно записываются обратно в память и загружаются из памяти.
@tkausl Re «Переменные стека не выделяются динамически». ОП никогда не говорил, что переменные стека распределяются динамически. Но они есть. Они действительно выделяются и освобождаются во время выполнения. Эти распределения и отмены распределения происходят автоматически, поэтому говорят, что они находятся в автоматическом хранилище. Но он по-прежнему динамически распределяется.
Компилятор может выполнить любую оптимизацию, чтобы удалить лишние объявления переменных или выделить для них место в регистрах. В противном случае, с точки зрения выделения стека, это всегда происходит во время выполнения, поскольку компилятор обычно не может заранее определить, сколько раз вызывается функция.
По какой-то причине плохие учебные материалы имеют тенденцию упрощать распределение переменных и говорить только о «стеке против кучи», игнорируя все остальное. Посмотрите Что выделяется в стеке и куче?
int x = 20;
сообщает компилятору использовать 20
вместо x
. Вот и все. Заметьте, я вообще не упомянул память. Фактически, следующие две программы на 100% эквивалентны:
printf( "%d\n", 20 );
int x = 20;
printf( "%d\n", x );
Пока он печатает 20␊
, детали того, как он это делает, не определены.
Но предположим, что он создает переменную в стеке.
компилятор уже выделяет память стека для этой переменной?
Нет. Весь смысл использования стека заключается в предоставлении временной памяти. И разрешить рекурсию.
Вообще говоря, любые локальные переменные, определенные в функции, создаются в момент входа в функцию, т. е. в стеке выделяется место для этих переменных, а затем это пространство освобождается при возврате функции.
Важным случаем здесь является рекурсия, когда функция может вызывать сама себя (прямо или косвенно). В этом случае существует экземпляр локальных переменных этой функции для каждого вызова функции. По этой причине невозможно заранее выделить «все» переменные.
Также обратите внимание, что использование стека является деталью реализации и не требуется стандартом C. Кроме того, оптимизации компилятора могут фактически не устанавливать дополнительное пространство в зависимости от того, как используется переменная.
I'm studying dynamic memory allocation
Переменные стека не выделяются динамически.