Что происходит, когда переменная выходит из области видимости?
7420 просмотра
3 ответа
В большинстве управляемых языков (т. Е. С GC) локальные переменные, которые выходят из области видимости, недоступны и имеют более высокий приоритет GC (следовательно, они будут освобождены первыми).
Теперь, C не является управляемым языком, что происходит с переменными, которые выходят за рамки этой области?
Я создал небольшой тест-кейс в C:
#include <stdio.h>
int main(void){
int *ptr;
{
// New scope
int tmp = 17;
ptr = &tmp; // Just to see if the memory is cleared
}
//printf("tmp = %d", tmp); // Compile-time error (as expected)
printf("ptr = %d\n", *ptr);
return 0;
}
Я использую GCC 4.7.3 для компиляции и программа выше печатает 17
, почему? И когда / при каких обстоятельствах будут освобождены локальные переменные?
Ответы (3)
16 плюса
Реальное поведение вашего примера кода определяется двумя основными факторами: 1) поведение не определено языком, 2) оптимизирующий компилятор сгенерирует машинный код, который физически не соответствует вашему C-коду.
Например, несмотря на то, что поведение не определено, GCC может (и будет) легко оптимизировать ваш код до простого
printf("ptr = %d\n", 17);
Это означает, что вывод, который вы видите, имеет очень мало общего с тем, что происходит с любыми переменными в вашем коде.
Если вы хотите, чтобы поведение вашего кода лучше отражало то, что происходит физически, вы должны объявить свои указатели volatile
. Поведение по-прежнему будет неопределенным, но, по крайней мере, оно ограничит некоторые оптимизации.
Теперь о том, что происходит с локальными переменными, когда они выходят из области видимости. Ничего физического не происходит. Типичная реализация выделяет достаточно места в программном стеке для хранения всех переменных на самом глубоком уровне вложенности блоков в текущей функции. Это пространство обычно выделяется в стеке за один раз при запуске функции и освобождается при выходе из функции.
Это означает, что память, ранее занимаемая, tmp
продолжает оставаться зарезервированной в стеке до выхода из функции. Это также означает, что одно и то же пространство стека может (и будет) использоваться разными переменными, имеющими примерно одинаковый уровень «глубины локальности» в соседних блоках. Пробел будет хранить значение последней переменной, пока какая-либо другая переменная, объявленная в некоторой переменной блока-брата, не переопределит ее. В вашем примере никто не переопределяет пространство, которое раньше занимало tmp
, поэтому вы, как правило, увидите, как значение 17
сохраняется в этой памяти без изменений.
Однако, если вы сделаете это
int main(void) {
volatile int *ptr;
volatile int *ptrd;
{ // Block
int tmp = 17;
ptr = &tmp; // Just to see if the memory is cleared
}
{ // Sibling block
int d = 5;
ptrd = &d;
}
printf("ptr = %d %d\n", *ptr, *ptrd);
printf("%p %p\n", ptr, ptrd);
}
вы увидите, что пространство, ранее занимаемое ранее, tmp
использовалось повторно, d
а его прежнее значение было переопределено. Второй printf
тип обычно выводит одинаковое значение указателя для обоих указателей.
5 плюса
Время жизни автоматического объекта заканчивается в конце блока, в котором он объявлен.
Доступ к объекту за пределами его времени жизни - неопределенное поведение в C.
Автор: ouah Размещён: 15.12.2012 12:55(C99, 6.2.4p2) «Если на объект ссылаются вне его времени жизни, поведение не определено. Значение указателя становится неопределенным, когда объект, на который он указывает, достигает конца своего времени жизни».
3 плюса
Локальные переменные размещаются в стеке. Они не «освобождены» в том смысле, в каком вы думаете о языках GC или о памяти, выделенной в куче. Они просто выходят из области видимости, и для встроенных типов код ничего не делает, а для объектов вызывается деструктор.
Доступ к ним за пределами их возможностей - неопределенное поведение. Вам просто повезло, так как никакой другой код не перезаписал эту область памяти ... пока.
Автор: Karoly Horvath Размещён: 15.12.2012 12:57Вопросы из категории :
- c Как вы форматируете unsigned long long int, используя printf?
- c What are the barriers to understanding pointers and what can be done to overcome them?
- c Как реализовать продолжения?
- c Как вы передаете функцию в качестве параметра в C?
- c Как получить список каталогов в C?
- c В чем разница между #include <filename> и #include "filename"?
- c Всегда ли выгодно использовать «goto» в языке, который поддерживает циклы и функции? Если так, то почему?
- c В чем разница между ++ i и i ++?
- c Есть ли разница в производительности между i ++ и ++ i в C?
- c Какой самый лучший бесплатный детектор утечки памяти для программы на C / C ++ и ее подключаемых библиотек DLL?
- memory-management Setting Objects to Null/Nothing after use in .NET
- memory-management Как работает пул автозапуска NSAutoreleasePool?
- memory-management Что и где находится стек и куча?
- memory-management Как имитировать ошибки выделения памяти
- memory-management Что такого плохого в использовании GC.Collect ()?
- memory-management Инструменты обнаружения утечки памяти
- memory-management Как принудительно прервать «обнаружен glibc *** free (): неверный указатель»
- memory-management В каких случаях я использую malloc и / или new?
- memory-management Элементы данных расположены в том же пространстве памяти, что и их объекты в C ++?
- memory-management Какое использование есть для "размещения новых"?