在 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
的生命周期从执行到达开口{
(进入函数)开始,到执行离开块时结束, 达到结束 }
(或通过其他方式,例如 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
离开内部块后不再存在,但生成的代码可能会因为更方便而将其留在堆栈中。
如果你想控制分配和释放,你需要使用malloc
和free
。
因为 char buffer[100];
被声明为 void foo()
的函数堆栈局部,当 void foo()
returns 时,buffer
的存储被释放以供重用和在那之后不再有效访问。
因此,您无需对 "deallocate buffer" 执行任何操作或可以执行任何操作,因为 buffer
是一个具有 自动存储持续时间的数组,因此会自动处理 =22=],例如参见:C11 Standard - 6.2.4 Storage durations of objects (p5)
假设我们有以下代码:
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
的生命周期从执行到达开口{
(进入函数)开始,到执行离开块时结束, 达到结束 }
(或通过其他方式,例如 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
离开内部块后不再存在,但生成的代码可能会因为更方便而将其留在堆栈中。
如果你想控制分配和释放,你需要使用malloc
和free
。
因为 char buffer[100];
被声明为 void foo()
的函数堆栈局部,当 void foo()
returns 时,buffer
的存储被释放以供重用和在那之后不再有效访问。
因此,您无需对 "deallocate buffer" 执行任何操作或可以执行任何操作,因为 =22=],例如参见:C11 Standard - 6.2.4 Storage durations of objects (p5)buffer
是一个具有 自动存储持续时间的数组,因此会自动处理