在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()