在 C 中释放局部定义的变量

Deallocating locally defined variables in C

假设我们有以下代码:

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

在 C 中是否有一种(最好是可移植的)方式来从运行时堆栈中释放 缓冲区(类似于 add esp, 100 in程序集), 在 foo() 之前 returns?

没有。在 C 中你能做的最好的事情就是使用范围:

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

并依靠编译器考虑在内部作用域退出后再次使用 buffer 的 100 个字节。不幸的是,标准不能保证这一点,您需要依赖编译器。例如,在具有 8192KB (ulimit -s) 堆栈 space 的典型 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;
}

(奇怪的转换是为了防止缓冲区变量被优化掉。)

当不使用优化进行构建时,程序将在某些编译器上溢出可用堆栈 space。例如,clang -O0 会崩溃,但 clang -O1 会为 buffer2 重用 buffer1 内存,并且两个地址将相同。换句话说,当作用域退出时,buffer1 在某种意义上已经是 "freed"。

另一方面,GCC 即使在 -O0.

也会进行此优化

它是一个自动变量,你不需要做任何事情,因为它会在离开它的范围时重新分配。在你的情况下,当你从函数

return

如果您想缩小范围,只需将其放在另一个范围内即可。

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 标准。

鉴于:

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

对象buffer生命周期从执行到达开口{(进入函数)开始,到执行离开块时结束, 达到结束 }(或通过其他方式,例如 gotobreakreturn 语句)。

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

如果你想控制分配和释放,你需要使用mallocfree

因为 char buffer[100]; 被声明为 void foo() 的函数堆栈局部,当 void foo() returns 时,buffer 的存储被释放以供重用和在那之后不再有效访问。

因此,您无需对 "deallocate buffer" 执行任何操作或可以执行任何操作,因为 buffer 是一个具有 自动存储持续时间的数组,因此会自动处理

=22=],例如参见:C11 Standard - 6.2.4 Storage durations of objects (p5)