C/C++ 储存周期
本文是我在知乎上的回答的复制,澄清了 C/C++ 中储存周期的概念,纠正了长久以来网络上对于二进制段和内存区段的混淆以及照本宣科的描述,解释了 auto
,register
,static
等关键字的历史。
网上常常有文章解释所谓的二进制区段或者内存区段,分为什么栈区全局区代码区和所谓的静态区全局区常量区,但实际上静态区全局区常量区都可以是一个区,这种解释都可以说是经典错误了。
首先需要澄清程序真正需要在内存里放什么:程序的代码,程序的函数执行栈,程序运行需要的的数据(比如字符串常量,以及所谓的全局静态对象,也包括函数内静态对象)。剩下的空间是自由区。同时程序运行还需要寄存器空间。
C 语言当初刚发明的时候,设计了一些语法特性,实际上这些语法特性不对应任何所谓的内存区段的划分,因为寄存器不在内存里。到了 C++ 的时候,C++ 找到了其中一个共性,实际上发明了一个概念,这个概念叫储存周期。
C/C++ 使用这几个词描述储存周期:register,automatic,static,thread,dynamic(C 中叫 allocated)。
于是,一个对象具有五种储存周期的任意一种。其中 register 表示寄存器储存周期,automatic 表示自动储存周期,static 表示静态储存周期(其中,全局对象要么是 extern
,要么是 static
,都具有静态储存周期)。那么实际上 register 对应对象储存在寄存器,automatic 对应对象储存在函数调用栈或者储存在寄存器,static 对应对象储存在数据区(数据区可以再划分,但是这个划分没什么意义),dynamic 对应对象储存在自由区。
在最早 C 语言发明 static
的时候,实际上和储存周期也没关系(当初 static
的唯一作用是声明具有内部链接,其他的具有外部链接 extern
),后来 C++ 借用 static
关键字来声明一些静态储存周期的对象。C/C++11 之后,增加了 thread_local
关键字用来声明一个线程储存周期的对象,线程储存储存周期的对象不在上面任何一个区段里。此外,C++ 废除了 register
关键字,并且取消了 auto
关键字用于声明自动储存周期,因为这是默认行为。
五种储存周期对应五个关键字,这 5 个关键字用于修饰对象的储存周期,其中 static 对应两种关键字 static
和 extern
,register 对应 register
,thread 对应 thread_local
,automatic 对应 auto
。动态储存周期的对象因为不需要声明所以没有关键字修饰。
C++ 中的对象有储存周期的同时,具有生命周期,同时 C++ 规定对象的生命周期小于等于其储存期。