1

假设我们有以下代码:

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

在 foo() 返回之前,C 中是否有一种(最好是可移植的)方法从运行时堆栈中释放缓冲区(类似于添加 esp,汇编中的 100) ?

4

4 回答 4

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

另一方面,GCC 甚至会在-O0.

于 2019-05-25T08:23:49.390 回答
2

鉴于:

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离开内部块后不再存在,但生成的代码可能会因为更方便而将其留在堆栈中。

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

于 2019-05-25T08:42:04.400 回答
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 标准。

于 2019-05-25T08:40:57.837 回答
1

因为char buffer[100];被声明为函数堆栈的本地,所以void foo()void foo()返回时,存储空间buffer被释放以供重用,并且在该点之后不再有效访问。

因此,您无需或可以做任何事情来“释放缓冲区”,因为它是一个具有自动存储持续时间buffer的数组,可以自动处理,例如:C11 Standard - 6.2.4 Storage duration of objects (p5)

于 2019-05-25T08:44:45.237 回答