Выделение локально определенных переменных в C - PullRequest
1 голос
/ 25 мая 2019

Предположим, у нас есть следующий фрагмент кода:

void foo() {
  char buffer[100];
}

Есть ли (предпочтительно переносимый) способ в C освободить буфер из стека времени выполнения (сродни add esp, 100 в сборке), перед foo () возвращается

Ответы [ 4 ]

5 голосов
/ 25 мая 2019

Нет. Лучшее, что вы можете сделать в C, это использовать области:

void foo()
{
    {
        char buffer[100];
    }
}

и положитесь на компилятор, чтобы рассмотреть 100 байтов buffer, доступных снова после выхода из внутренней области. К сожалению, это не гарантируется стандартом, и вам нужно зависеть от компилятора. Например, рассмотрим следующую программу на типичном компьютере Linux с размером стека 8192 КБ (ulimit -s):

#include <stdio.h>

int main(void)
{
    {
        char buffer1[8192 * 800] = { 0 };
        ((char volatile *)buffer1)[0] = buffer1[0];
        printf("%p\n", buffer1);
    }

    {
        char buffer2[8192 * 800] = { 0 };
        ((char volatile *)buffer2)[0] = buffer2[0];
        printf("%p\n", buffer2);
    }

    return 0;
}

(странное приведение - предотвратить оптимизацию буферных переменных.)

Программа переполняет доступное пространство стека в некоторых компиляторах, если не выполняет сборку с оптимизацией. Например, clang -O0 приведет к сбою, но clang -O1 будет повторно использовать память buffer1 для buffer2, и оба адреса будут одинаковыми. Другими словами, buffer1 был «освобожден» в некотором смысле при выходе из области действия.

GCC, с другой стороны, выполнит эту оптимизацию даже при -O0.

2 голосов
/ 25 мая 2019

Дано:

void foo(void) {
  char buffer[100];
}

время жизни объекта buffer начинается, когда выполнение достигает открытия { (при входе в функцию), и заканчивается, когда выполнение покидаетблок, достигнув закрытия } (или с помощью других средств, таких как оператор goto, break или return).

Нет никакого способа закончить время жизни buffer, кромеоставив блок.Если вы хотите иметь возможность освободить его, вы должны распределить его другим способом.Например, если вы выделяете объект, вызывая malloc(), вы можете (и в значительной степени обязаны) освободить его, вызвав free:

void foo(void) {
    char *buffer_ptr = malloc(100);
    if (buffer_ptr == NULL) /* error handling code here */
    /* ... */
    if (we_no_longer_need_the_buffer) {
        free(buffer_ptr);
    }
    /* now buffer_ptr is a dangling pointer */
}

Альтернативой является ограничение времени жизни bufferопределяя его во вложенном блоке:

void foo(void) {
    /* ... */
    {
        char buffer[100];
        /* ... */
    }
    /* buffer's lifetime has ended */
}

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

Если вы хотите контролировать распределение и освобождение, вам нужноиспользовать malloc и free.

1 голос
/ 25 мая 2019

Поскольку char buffer[100]; объявлено локальным для стека функций для void foo(), при возврате void foo() хранилище для buffer освобождается для повторного использования и больше не действует для доступа после этой точки.

Так что вам ничего не нужно делать или делать, чтобы "освободить буфер ", поскольку это обрабатывается автоматически, поскольку buffer является массивом с длительностью автоматического хранения например см .: C11 Standard - 6.2.4 Длительность хранения объектов (p5)

1 голос
/ 25 мая 2019

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

, если хотите уменьшить область, просто поместите ее в другую область.

foo()
{
      for(... .)
      {
              // if defined here it will be only in the for loop  scope
       }

       {
           // if defined here it will be only in this internal scope
        }

}

с учетом того, что для этого требуется стандарт С, который позволяет это.

...