C++存储区域

来源:互联网 发布:程序员客栈签约 编辑:程序博客网 时间:2024/06/05 17:12

对一个C++变量来说,有两个属性非常重要:作用域和生命周期,它们从两个不同的维度描述了一个变量--时间和空间。顾名思义,作用域就是一个变量可以被引用的范围,如:全局作用域、文件作用域、局部作用域;而生命周期就是这个变量可以被引用的时间段。不同生命周期的变量,在程序内存中的分布位置是不一样的。一个程序的内存分为代码区、全局数据区、堆区、栈区,不同的内存区域,对应不同的生命周期。

 

<span style="font-size:18px;">一个由C/C++编译的程序占用的内存分为以下几个部分</span>
<span style="font-size:18px;">1、栈区(stack)— 程序运行时由编译器自动分配,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。2、堆区(heap) — 在内存开辟另一块存储区域。一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。3、全局区(静态区)(static)—编译器编译时即分配内存。全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 - 程序结束后由系统释放4、文字常量区 —常量字符串就是放在这里的。 程序结束后由系统释放。5、程序代码区—存放函数体的二进制代码。</span>

注意:静态局部变量和静态全局变量
属于静态存储方式的量不一定就是静态变量。 例如:全局变量虽属于静态存储方式,但不一定是静态变量,必须由 static加以定义后才能成为静态外部变量,或称静态全局变量。
把局部变量改变为静态变量后是改变了它的存储方式,即改变了它的生存期。
把全局变量改变为静态变量后是改变了它的作用域,限制了它的使用范围。

请看下面例子:

[cpp] view plaincopyprint?
  1. #include<iostream>  
  2. using namespace std;  
  3.   
  4.   
  5. char* func()  
  6. {  
  7.     //char str[]="Hello,world\n"; //error 字符串数组,局部变量,存储在栈区;可以修改  
  8.     char *str="Hello,world\n";    //okay  字符串常量,存储在常量区;不可以修改  
  9.     return str;  
  10. }  
  11.   
  12.   
  13. int main()  
  14. {  
  15.     cout << func();  
  16.     return 0;  
  17. }  

     有很多方法来指定一个变量的作用域和生命周期。最常见的,如:{ }、static修饰符等。下面按照作用域与生命周期来对变量做一个分类:

 

全局变量

  • 作用域:全局作用域(全局变量只需在一个源文件中定义,就可以作用于所有的源文件。)
  • 生命周期:程序运行期一直存在
  • 引用方法:其他文件中要使用必须用extern 关键字声明要引用的全局变量。
  • 内存分布:全局数据区
  • 注意:如果在两个文件中都定义了相同名字的全局变量,连接出错:变量重定义
  • 例子:

[cpp] view plaincopyprint?
  1. //defime.cpp  
  2. int g_iValue = 1;  
  3.   
  4. //main.cpp  
  5. extern int g_iValue;  
  6.   
  7. int main()  
  8. {  
  9.     cout << g_iValue;  
  10.     return 0;  
  11. }  

 

全局静态变量

  •  作用域:文件作用域(只在被定义的文件中可见。)
  • 生命周期:程序运行期一直存在
  • 内存分布:全局数据区
  • 定义方法:static关键字,const 关键字
  • 注意:只要文件不互相包含,在两个不同的文件中是可以定义完全相同的两个静态变量的,它们是两个完全不同的变量
  • 例子:

[cpp] view plaincopyprint?
  1. const int iValue_1;  
  2. static const int iValue_2;  
  3. static int iValue_3;  
  4.   
  5. int main()  
  6. {  
  7.     return 0;  
  8. }  

 

静态局部变量

  • 作用域:局部作用域(只在局部作用域中可见)
  • 生命周期:程序运行期一直存在
  • 内存分布:全局数据区
  • 定义方法:局部作用域用中用static定义
  • 注意:只被初始化一次,多线程中需加锁保护
  • 例子:

[cpp] view plaincopyprint?
  1. void function()  
  2. {  
  3.     static int iREFCounter = 0;  
  4. }  

 

局部变量

  • 作用域:局部作用域(只在局部作用域中可见)
  • 生命周期:程序运行出局部作用域即被销毁
  • 内存分布:栈区
  • 注意:auto指示符标示

     

有如下笔试题:

全局变量放在(数据段);函数内部变量Static int ncount 放在(数据段);函数内部变量char *p="AAA",p的位置在(堆栈);指向空间的位置(数据段);函数内变量char *p=new char;p的位置(堆);指向空间的位置(数据段);

还有一点要说明,掌握static关键字的使用很关键。以下是引用别人的一些经验之谈:

Tips:

  1. 若全局变量仅在单个C文件中访问,则可以将这个变量修改为静态全局变量,以降低模块间的耦合度;
  2. 若全局变量仅由单个函数访问,则可以将这个变量改为该函数的静态局部变量,以降低模块间的耦合度;
  3. 设计和使用访问动态全局变量、静态全局变量、静态局部变量的函数时,需要考虑重入问题,因为他们都放在静态数据存储区,全局可见;
  4. 如果我们需要一个可重入的函数,那么,我们一定要避免函数中使用static变量(这样的函数被称为:带“内部存储器”功能的的函数)
  5. 函数中必须要使用static变量情况:比如当某函数的返回值为指针类型时,则必须是static的局部变量的地址作为返回值,若为auto类型,则返回为错指针。
  6. 用new关键字或者malloc函数分配的内存空间既不在栈中,也不在静态数据区,在堆中。

堆和栈的区别:

   1、管理方式不同;对于栈来讲,是由编译器自动管理,无需我们手工控制;对于堆来说,释放工作由程序员控制,容易产生memory leak。
    2、空间大小不同;栈的空间有限,堆有很大的自由存储区

    3、能否产生碎片不同;堆和栈相比,由于大量new/delete的使用,容易造成大量的内存碎片;由于没有专门的系统支持,效率很低;由于可能引发用户态和核心态的切换,内存的申请,代价变得更加昂贵。所以栈在程序中是应用最广泛的,就算是函数的调用也利用栈去完成,函数调用过程中的参数,返回地址,EBP和局部变量都采用栈的方式存放。所以,我们推荐大家尽量用栈,而不是用堆。

    4、分配效率不同;在栈上的数组比指针所指向的字符串(例如堆)快。

0 0
原创粉丝点击