在C语言中释放本地定义的变量

在C语言中释放本地定义的变量,c,memory-management,local-variables,stack-pointer,static-allocation,C,Memory Management,Local Variables,Stack Pointer,Static Allocation,假设我们有以下代码: void foo() { char buffer[100]; } 在foo()返回之前,C中是否有(最好是可移植的)方法来从运行时堆栈中释放缓冲区(类似于在汇编中添加esp,100)?否。在C中,最好使用作用域: void foo() { { char buffer[100]; } } 并依赖编译器在内部范围退出后重新考虑100个字节的代码>缓冲区< /代码>。不幸的是,标准并不能保证这一点,您需要依赖于编译器。例如,在一个典型的Li

假设我们有以下代码:

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

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

否。在C中,最好使用作用域:

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

并依赖编译器在内部范围退出后重新考虑100个字节的代码>缓冲区< /代码>。不幸的是,标准并不能保证这一点,您需要依赖于编译器。例如,在一个典型的Linux机器上考虑下面的程序,它的堆栈空间为8192kb(<代码> ulimIT-s<代码>):

#包括
内部主(空)
{
{
char buffer1[8192*800]={0};
((char volatile*)buffer1)[0]=buffer1[0];
printf(“%p\n”,buffer1);
}
{
字符缓冲区2[8192*800]={0};
((char volatile*)buffer2)[0]=buffer2[0];
printf(“%p\n”,buffer2);
}
返回0;
}
(奇怪的强制转换是为了防止缓冲区变量被优化掉。)

当不使用优化构建时,该程序将溢出某些编译器上的可用堆栈空间<例如,code>clang-O0将崩溃,但
clang-O1
将重用
buffer1
内存用于
buffer2
,两个地址将相同。换句话说,当作用域退出时,
buffer1
在某种意义上被“释放”


另一方面,即使在
-O0

否时,GCC也会进行此优化。在C中,最好使用范围:

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

并依赖编译器在内部范围退出后重新考虑100个字节的代码>缓冲区< /代码>。不幸的是,标准并不能保证这一点,您需要依赖于编译器。例如,在一个典型的Linux机器上考虑下面的程序,它的堆栈空间为8192kb(<代码> ulimIT-s<代码>):

#包括
内部主(空)
{
{
char buffer1[8192*800]={0};
((char volatile*)buffer1)[0]=buffer1[0];
printf(“%p\n”,buffer1);
}
{
字符缓冲区2[8192*800]={0};
((char volatile*)buffer2)[0]=buffer2[0];
printf(“%p\n”,buffer2);
}
返回0;
}
(奇怪的强制转换是为了防止缓冲区变量被优化掉。)

当不使用优化构建时,该程序将溢出某些编译器上的可用堆栈空间<例如,code>clang-O0将崩溃,但
clang-O1
将重用
buffer1
内存用于
buffer2
,两个地址将相同。换句话说,当作用域退出时,
buffer1
在某种意义上被“释放”


另一方面,即使在
-O0

时,GCC也会进行此优化。这是一个自动变量,您无需执行任何操作,因为在离开它的范围时,它将被重新分配。在您的情况下,当您从函数返回时

如果你想缩小范围,就把它放在另一个范围内

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

它是自动变量,您不必做任何事情,因为当离开它的范围时,它将被重新分配。在您的情况下,当您从函数返回时

如果你想缩小范围,就把它放在另一个范围内

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];
}
对象
缓冲区的生存期从执行到达开始
{
(在进入函数时)开始,到执行离开块、到达结束
}
(或通过其他方式,如
转到
中断
返回
语句)结束

除了离开块,没有办法结束
缓冲区的生存期。如果你想解除分配它,你必须以其他方式分配它。例如,如果您通过调用
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 */
}
另一种方法是通过在嵌套块中定义
缓冲区来限制其生存期:

void foo(void) {
    /* ... */
    {
        char buffer[100];
        /* ... */
    }
    /* buffer's lifetime has ended */
}
但仅仅因为当控件离开内部块时,
缓冲区的生存期就结束了,这并不能保证它在物理上被解除分配。在抽象机器中,
buffer
在离开内部块后不再存在,但是生成的代码可能会因为更方便而将其留在堆栈上

如果您想要控制分配和解除分配,您需要使用
malloc
free

给定:

void foo(void) {
  char buffer[100];
}
对象
缓冲区的生存期从执行到达开始
{
(在进入函数时)开始,到执行离开块、到达结束
}
(或通过其他方式,如
转到
中断
返回
语句)结束

除了离开块,没有办法结束
缓冲区的生存期。如果你想解除分配它,你必须以其他方式分配它。例如,如果您通过调用
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 */
}
另一种方法是通过在嵌套块中定义
缓冲区来限制其生存期:

void foo(void) {
    /* ... */
    {
        char buffer[100];
        /* ... */
    }
    /* buffer's lifetime has ended */
}
但仅仅因为当控件离开内部块时,
缓冲区的生存期就结束了,这并不能保证它在物理上被解除分配。在抽象机器中,
buffer
在离开内部块后不再存在,但是生成的代码可能会因为更方便而将其留在堆栈上


如果您想要控制分配和解除分配,您需要使用
malloc
free
,因为
字符缓冲区[100]void foo()