在C中取消分配局部定义的变量

时间:2019-05-25 08:06:46

标签: c memory-management local-variables stack-pointer static-allocation

假设我们有以下代码段:

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

在C中是否有一种(最好是可移植的)方式从运行时堆栈中释放 buffer (类似于 add esp,100 在程序集中),在foo之前()返回

4 个答案:

答案 0 :(得分:5)

不。您可以在C语言中做的最好的事情就是使用范围:

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

,并依靠编译器考虑在内部范围退出之后再次使用buffer的100字节。不幸的是,这不是标准所保证的,您需要依赖编译器。例如,在具有8192KB(ulimit -s)堆栈空间的典型Linux机器上考虑以下程序:

#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 -O1buffer1的内存重新用于buffer2,并且两个地址将相同。换句话说,从某种意义上说,buffer1在范围退出时已经“释放”。

另一方面,即使在-O0,GCC也会进行此优化。

答案 1 :(得分:2)

给出:

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

对象buffer lifetime 在执行到达开始{(在函数入口处)时开始,并在执行离开该块并到达结束{ {1}}(或通过其他方式,例如}gotobreak语句)。

除了离开该块,无法结束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在离开内部块之后不再存在,但是生成的代码可能只是因为更方便而将其保留在堆栈中。

如果要控制分配和释放,则需要使用buffermalloc

答案 2 :(得分:1)

它是自动变量,您无需执行任何操作,因为它将在离开它的范围时被重新分配。您从函数返回时的情况

如果要缩小范围,可以将其放在另一个范围内。

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
        }

}

请记住,它需要允许它的C标准。

答案 3 :(得分:1)

Because char buffer[100]; is declared local to the function stack for void foo(), when void foo() returns, the storage for buffer is released for reuse and is no longer valid for access after that point.

So there is nothing you need to do, or can do, to "deallocate buffer" as that is handled automatically by virtue of buffer being an array with automatic storage duration, e.g. see: C11 Standard - 6.2.4 Storage durations of objects (p5)

转换