Если я создаю переменную в новом наборе фигурных скобок, эта переменная выталкивается из стека на закрывающей скобке или она висит до конца функции? Например:
void foo() {
int c[100];
{
int d[200];
}
//code that takes a while
return;
}
Будете d
занимать память во время code that takes a while
раздела?
Ответы:
Нет, фигурные скобки не действуют как кадр стека. В C фигурные скобки обозначают только область именования, но ничего не разрушается и ничего не выталкивается из стека, когда управление выходит из него.
Как программист, пишущий код, вы часто можете думать о нем, как о стековом фрейме. Идентификаторы, объявленные в фигурных скобках, доступны только в фигурных скобках, поэтому, с точки зрения программиста, они как бы помещаются в стек при объявлении, а затем извлекаются при выходе из области действия. Тем не менее, компиляторы не должны генерировать код, который что-то толкает / выталкивает при входе / выходе (и, как правило, это не так).
Также обратите внимание, что локальные переменные могут вообще не использовать пространство стека: они могут храниться в регистрах ЦП или в каком-либо другом месте вспомогательного хранилища или полностью оптимизироваться.
Таким образом,
d
массив, теоретически, может потреблять память для всей функции. Тем не менее, компилятор может оптимизировать его или разделить его память с другими локальными переменными, чьи времена использования не перекрываются.источник
Время, в течение которого переменная фактически занимает память, очевидно зависит от компилятора (и многие компиляторы не корректируют указатель стека, когда внутренние блоки вводятся и выходятся внутри функций).
Однако тесно связанный, но, возможно, более интересный вопрос заключается в том, разрешено ли программе получать доступ к этому внутреннему объекту вне внутренней области (но внутри содержащей функции), то есть:
(Другими словами: разрешено ли компилятору освобождать
d
, даже если на практике большинство этого не делает?).Ответ в том , что компилятор будет разрешено освобождать
d
, и доступ кp[0]
которой комментарий указывает на это неопределенное поведение (программа не имеет права доступа на внутренний объект за пределами внутреннего объема). Соответствующая часть стандарта C - 6.2.4p5:источник
Ваш вопрос недостаточно ясен, чтобы на него можно было ответить однозначно.
С одной стороны, компиляторы обычно не выполняют никакого выделения-освобождения локальной памяти для областей вложенных блоков. Локальная память обычно выделяется только один раз при входе в функцию и освобождается при выходе из функции.
С другой стороны, когда время жизни локального объекта заканчивается, память, занятая этим объектом, может быть повторно использована для другого локального объекта позже. Например, в этом коде
оба массива обычно занимают одну и ту же область памяти, а это означает, что общий объем локального хранилища, необходимый для функции,
foo
является тем, что необходимо для самого большого из двух массивов, а не для обоих из них одновременно.Правильно ли считать, что последний
d
продолжает занимать память до конца работы в контексте вашего вопроса, решать вам.источник
Это зависит от реализации. Я написал короткую программу для проверки того, что делает gcc 4.3.4, и он выделяет все пространство стека сразу в начале функции. Вы можете проверить сборку, которую создает gcc, используя флаг -S.
источник
Нет, d [] не будет в стеке до конца процедуры. Но alloca () отличается.
Изменить: Кристофер Джонсон (и Саймон и Дэниел) правы , и мой первоначальный ответ был неправильным . С gcc 4.3.4.on CYGWIN, код:
дает:
Живи и учись! И быстрый тест, кажется, показывает, что AndreyT также прав насчет множественных распределений.
Добавлено гораздо позже : приведенный выше тест показывает, что документация gcc не совсем верна. В течение многих лет он сказал (выделение добавлено):
источник
alloca
функцию. Я действительно удивлен, что Cygwin GCC сделает это. Это даже не массив переменной длины, так что IDK, почему вы подняли это.Они могут. Они не могут. Ответ, который, я думаю, вам действительно нужен: никогда не предполагайте ничего. Современные компиляторы делают все виды архитектуры и волшебства, связанного с реализацией. Напишите свой код просто и разборчиво для людей, и пусть компилятор сделает хорошие вещи. Если вы пытаетесь создать код вокруг компилятора, то вам нужны проблемы, и проблема, с которой вы обычно сталкиваетесь в таких ситуациях, обычно ужасно тонкая и ее трудно диагностировать.
источник
Ваша переменная
d
обычно не выталкивается из стека. Фигурные скобки не обозначают кадр стека. В противном случае вы не сможете сделать что-то вроде этого:Если фигурные скобки вызвали истинный push / pop стека (как вызов функции), то приведенный выше код не будет компилироваться, потому что код внутри фигурных скобок не сможет получить доступ к переменной,
var
которая находится за пределами фигурных скобок (точно так же, как вложенные элементы). функция не может напрямую обращаться к переменным в вызывающей функции). Мы знаем, что это не так.Фигурные скобки просто используются для определения объема. Компилятор будет обрабатывать любой доступ к «внутренней» переменной снаружи вложенных фигурных скобок как недопустимый, и он может повторно использовать эту память для чего-то другого (это зависит от реализации). Тем не менее, он не может быть извлечен из стека, пока не завершится функция включения.
Обновление: вот что говорит C-спецификация . Относительно объектов с автоматическим сроком хранения (раздел 6.4.2):
В этом же разделе термин «время жизни» определяется как (выделено мной):
Ключевое слово здесь, конечно, «гарантировано». Как только вы покидаете область действия внутреннего набора фигурных скобок, время жизни массива заканчивается. Хранилище может выделяться или не выделяться для него (ваш компилятор может повторно использовать пространство для чего-то другого), но любые попытки доступа к массиву вызывают неопределенное поведение и приводят к непредсказуемым результатам.
В спецификации C нет понятия стековых фреймов. Он говорит только о том, как будет вести себя результирующая программа, и оставляет детали реализации компилятору (в конце концов, реализация будет выглядеть совершенно иначе на CPU без стека, чем на CPU с аппаратным стеком). В спецификации C нет ничего, что указывало бы, где кадр стека закончится или не закончится. Единственный реальный способ узнать это - скомпилировать код на вашем конкретном компиляторе / платформе и изучить получившуюся сборку. Текущий набор параметров оптимизации вашего компилятора, вероятно, также сыграет в этом свою роль.
Если вы хотите убедиться, что массив
d
больше не потребляет память во время работы вашего кода, вы можете либо преобразовать код в фигурных скобках в отдельную функцию, либо явноmalloc
иfree
в память вместо использования автоматического хранения.источник
Я считаю, что он выходит из области видимости, но не выводится из стека до тех пор, пока не вернется функция. Таким образом, он по-прежнему будет занимать память в стеке до тех пор, пока функция не будет завершена, но недоступен после первой закрывающей фигурной скобки.
источник
Там уже было дано много информации о стандарте, указывающей, что он действительно специфичен для реализации.
Итак, один эксперимент может представлять интерес. Если мы попробуем следующий код:
Используя gcc, мы получаем здесь два раза один и тот же адрес: Coliro
Но если мы попробуем следующий код:
Используя gcc, мы получаем два разных адреса: Coliro
Таким образом, вы не можете быть уверены, что происходит.
источник