Что происходит, когда переменная выходит из области видимости?

c memory-management

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, почему? И когда / при каких обстоятельствах будут освобождены локальные переменные?

Автор: Lukas Knuth Источник Размещён: 12.11.2019 09:07

Ответы (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тип обычно выводит одинаковое значение указателя для обоих указателей.

Автор: AnT Размещён: 15.12.2012 12:57

5 плюса

Время жизни автоматического объекта заканчивается в конце блока, в котором он объявлен.

Доступ к объекту за пределами его времени жизни - неопределенное поведение в C.

(C99, 6.2.4p2) «Если на объект ссылаются вне его времени жизни, поведение не определено. Значение указателя становится неопределенным, когда объект, на который он указывает, достигает конца своего времени жизни».

Автор: ouah Размещён: 15.12.2012 12:55

3 плюса

Локальные переменные размещаются в стеке. Они не «освобождены» в том смысле, в каком вы думаете о языках GC или о памяти, выделенной в куче. Они просто выходят из области видимости, и для встроенных типов код ничего не делает, а для объектов вызывается деструктор.

Доступ к ним за пределами их возможностей - неопределенное поведение. Вам просто повезло, так как никакой другой код не перезаписал эту область памяти ... пока.

Автор: Karoly Horvath Размещён: 15.12.2012 12:57
Вопросы из категории :
32x32