堆栈和堆上创建的变量的生命周期之间的差异?

时间:2015-09-24 14:10:18

标签: c

我知道在动态内存分配的情况下使用堆,否则使用堆栈。 我试过Difference between static memory allocation and dynamic memory allocation 我知道差异,但混乱是关于他们的生命。

2 个答案:

答案 0 :(得分:8)

首先,堆栈和堆是实现细节(单词“stack”和“heap”不会出现在C language standard中的任何位置)。相反,该标准讨论了对象的存储持续时间(第6.2.4节)。

自C2011起,有四个存储持续时间:静态自动线程已分配

具有静态存储持续时间的对象具有在整个程序生命周期内延长的生命周期 1 。也就是说,在加载程序时为它们留出内存,并在程序退出时释放该内存。在文件范围(在任何函数之外)或使用static关键字声明的对象具有静态存储持续时间。静态对象的存储通常从二进制映像本身中分配(对于ELF,这将包括.data.rodata.bss部分);也就是说,堆栈或堆之外的东西。

具有自动存储持续时间的对象的生命周期从创建它们的块的入口延伸,直到块退出 2 。如果以递归方式输入块,则会创建一个新对象。在没有static关键字的块中声明的对象具有自动存储持续时间。具有自动存储持续时间的对象通常从运行时硬件堆栈分配,但并非所有体系结构都有堆栈。

具有线程存储持续时间的对象的生命周期延长到创建它们的线程的执行时间。使用_Thread_local关键字声明的对象具有线程存储持续时间。我认为线程局部对象的分配方式与自动变量相同,但这可能是错误的;我从未使用过C2011本机线程,所以我不能肯定地说。

具有已分配存储持续时间的对象的生命周期从分配malloccallocrealloc之后延长,直到通过调用{{1}显式释放它们为止}。具有分配的存储持续时间的对象通常从堆中分配(尽管并非所有体系结构都具有堆本身)。事情变得混乱的地方是将分配的对象与指向它的对象区分开来。给出以下代码:

free

我们已经分配了三个对象。在函数int *foo( void ) { int *bar = malloc( sizeof *bar * 10 ); // do stuff with bar return bar; } void bletch( void ) { int *blurga = foo(); // do stuff with blurga free( blurga ); } 中,我们使用自动存储持续时间分配指针对象(由变量foo引用);它的生命周期是函数bar的生命周期。在函数foo中,我们使用自动存储持续时间分配另一个指针对象(由变量bletch引用);它的生命周期延伸到函数blurga的生命周期。

第三个对象是一个足以容纳10个bletch个对象的缓冲区。它的生命周期从int中的malloc来电延伸到foo中的free来电;它的生命周期与任何函数或块的生命周期无关。

<小时/> 1。对象的生命周期是程序执行中保证为该对象保留存储的时间。请注意,对象的生存期与引用该对象的标识符的范围不同。即使可以在块条目处分配对象的存储器,但是引用它的标识符的范围可能更受限制。

假设以下代码:
bletch
变量void foo() { printf( "entered foo\n" ); int i = 0; while ( i < 10 ) printf( "%d\n", i++ ); }范围从其声明的结尾延伸到块的结尾;但是,整数对象i生命周期是指从块入口延伸到块出口。

2.实际上,大多数编译器会在函数入口处为所有块作用域变量留出存储空间,即使某些变量可能是函数中块的本地变量。但是,最好假设i对象的生命周期仅延伸到包含它的块。

答案 1 :(得分:2)

堆栈变量具有局部范围,这意味着它们仅在声明它们的{}对中有效去引用。虽然动态分配的变量在程序调用{​​{1}}之前有效。

更正确的名称是局部变量,因为局部变量也可能最终在CPU寄存器中分配,而不是总是在堆栈中。形式上,它们在C标准中被称为自动存储持续时间的变量,这意味着编译器会自动决定哪个是分配它们的最佳位置。