Компиляторы C предварительно выделяют каждую переменную, существующую в программе? Или они выделяют во время работы программы?

Например, когда я определяю переменную, например int x = 20;, в функции, которую можно вызвать в основной функции, выделяет ли компилятор уже стековую память для этой переменной? Потому что, как я уже сказал, это переменная, которую можно вызывать, но можно и не вызывать, и программа может завершиться и никогда не вызвать ее.

Я изучаю динамическое распределение памяти и варианты использования malloc, и я читал кое-что, что привело меня в полное замешательство, лол.

I'm studying dynamic memory allocation Переменные стека не выделяются динамически.
tkausl 13.08.2024 16:03

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

Raymond Chen 13.08.2024 16:03

Память, необходимая для x, помещается в стек каждый раз, когда вызывается функция (или, конечно, 0 раз, если функция никогда не вызывается). Это происходит во время выполнения, компилятор не резервирует/предварительно выделяет память. Если окажется, что у вас недостаточно памяти, вы получите переполнение стека или ошибку нехватки памяти.

Jack Leow 13.08.2024 16:05

Люди могут дать вам ответы и объяснения, но, честно говоря, я думаю, что единственный способ добиться реальной ясности в том, как это работает, — это пойти и немного изучить ассемблер.

Verpous 13.08.2024 16:12

Вы знаете о рекурсии? Когда вы вызываете функцию foo изнутри foo, как бы вы предварительно выделили память для каждого вложенного вызова этой функции? Вам нужен отдельный int x для каждого из вложенных вызовов.

Gerhardh 13.08.2024 16:32

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

Martin Brown 13.08.2024 16:48

@tkausl Re «Переменные стека не выделяются динамически». ОП никогда не говорил, что переменные стека распределяются динамически. Но они есть. Они действительно выделяются и освобождаются во время выполнения. Эти распределения и отмены распределения происходят автоматически, поэтому говорят, что они находятся в автоматическом хранилище. Но он по-прежнему динамически распределяется.

ikegami 13.08.2024 17:18
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
7
79
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

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

По какой-то причине плохие учебные материалы имеют тенденцию упрощать распределение переменных и говорить только о «стеке против кучи», игнорируя все остальное. Посмотрите Что выделяется в стеке и куче?

Ответ принят как подходящий

int x = 20; сообщает компилятору использовать 20 вместо x. Вот и все. Заметьте, я вообще не упомянул память. Фактически, следующие две программы на 100% эквивалентны:

printf( "%d\n", 20 );
int x = 20;
printf( "%d\n", x );

Пока он печатает 20␊, детали того, как он это делает, не определены.


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

компилятор уже выделяет память стека для этой переменной?

Нет. Весь смысл использования стека заключается в предоставлении временной памяти. И разрешить рекурсию.

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

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

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

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