假设我们有以下代码:
void foo() {
char buffer[100];
}
在 foo() 返回之前,C 中是否有一种(最好是可移植的)方法从运行时堆栈中释放缓冲区(类似于添加 esp,汇编中的 100) ?
假设我们有以下代码:
void foo() {
char buffer[100];
}
在 foo() 返回之前,C 中是否有一种(最好是可移植的)方法从运行时堆栈中释放缓冲区(类似于添加 esp,汇编中的 100) ?
不,你可以在 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.
鉴于:
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离开内部块后不再存在,但生成的代码可能会因为更方便而将其留在堆栈中。
如果你想控制分配和释放,你需要使用mallocand free。
它是自动变量,您不必做任何事情,因为它会在离开它的范围时重新分配。在您从函数返回时
如果您想缩小范围,只需将其放在另一个范围内。
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 标准。
因为char buffer[100];被声明为函数堆栈的本地,所以void foo()当void foo()返回时,存储空间buffer被释放以供重用,并且在该点之后不再有效访问。
因此,您无需或可以做任何事情来“释放缓冲区”,因为它是一个具有自动存储持续时间buffer的数组,可以自动处理,例如:C11 Standard - 6.2.4 Storage duration of objects (p5)