存储持续性、作用域和链接性
C++用三种(C++11是四种)不同方案存储数据:
- 自动存储持续性:在函数定义中声明的变量(包括函数参数)的存储持续性为自动的。在程序开始执行其所属的函数和代码块时被创建,在执行完函数或代码后,它们使用的内存被释放。C++有两种该类型的变量。
- 静态存储持续性:在函数定义外定义的变量和使用关键字static定义的变量的存储持续性都为静态的。它们在程序整个运行过程都在。C++有三种该类型的变量。
- 线程存储持续性(C++11):如果变量是使用关键字thread_local声明的,则其生命周期与所属的线程一样长。
- 动态存储性:用new运算符分配的内存将一直存在,直到使用delete运算符将其释放或程序结束为止。有时被称为自由存储或堆。
作用域和链接
作用域:描述名称在文件的多大范围内可见。
链接性:描述名称如何在不同单元间共享。
自动存储持续性
在默认情况下,在函数中声明的函数参数和变量的存储持续性为自动,作用域为局部,没有链接性。
...
//整个部分teledeli #1都存在
{
int teledeli; //teledeli #1 可见
....
....
{ //teledeli #2存在,隐藏了teledeli #1
int teledeli;
....
}
''''
....
}
自动变量的数目随着函数的开始和阶数而增减,因此程序在运行时利用栈来管理变量的增减。
寄存器变量:用CPU寄存器来存储自动变量
register int count;
静态持续变量
三种链接性:
- 外部链接性(可在其他文件中访问)
- 内部链接性(只能在当前文件中访问)
- 无链接性(只能在当前函数和代码块中访问)
三种链接性在整个程序执行期间都存在,静态变量的数目在程序运行期间是不变的。
...
int global = 1000;//外部链接性
static int one_file = 50;//内部链接性
int main()
{
...
}
void funct1(int n)
{
static int cnt = 0;//无链接性
int llama = 0;//自动变量
...
}
5种变量存储方式
存储描述 | 持续性 | 作用域 | 链接性 | 如何声明 |
---|---|---|---|---|
自动 | 自动 | 代码块 | 无 | 在代码块中 |
寄存器 | 自动 | 代码块 | 无 | 在代码块中,使用关键字register |
静态,无链接性 | 静态 | 代码块 | 无 | 在代码块中,使用关键字static |
静态,外部链接性 | 静态 | 文件 | 外部 | 不在任何函数内 |
静态,内部链接性 | 静态 | 文件 | 内部 | 不在任何函数内,使用关键字static |
静态持续性、外部链接性
在每个使用外部变量的文件中,都必须声明它,但是C++单定义规则指出,变量只能有一次定义,为了满足需求有两种变量声明:
- 定义声明,给变量分配存储空间
- 引用声明,引用已有的变量
引用声明使用关键字extern,且不进行初始化;否则,声明为定义声明,导致分配存储空间。
静态持续性、内部链接性
如果文件定义一个static内部链接变量,其名称与另一个文件中声明的静态外部链接性变量相同,则在该文件中,内部链接变量隐藏外部链接变量。
静态存储性持续、无连接性
将static限定符用于在代码块中定义的变量,这意味着变量只在该代码块中可用,但是它在该代码块不处于活动状态时仍存在。
说明符合限定符
存储说明符:
- auto(C++11中不再是说明符,用于自动类型推断)
- register
- static
- extern
- thread_local(C++11新增,变量的持续性与所属线程的持续性相同)
- mutable(用它来指出,即使结构或类变量为const,其某个成员也可以被修改)
cv-限定符
- const
- volatile
const限定符:const全局变量的链接性是内部的,全局const定义就像使用了static一样。
const int fingers = 10; //same as static const int fingers = 10;
int main()
{
...
volatile限定符:用它声明的类型变量表示可以被某些编译器未知的因素更改,遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问,当要求使用 volatile 声明的变量的值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。而且读取的数据立刻被保存。
函数和链接性
C++不允许在一个函数中定义另外一个函数,因此所有函数的存储持续性都自动为静态的,默认情况下,函数的链接性为外部的,即可在文件间共享。可以用extern指出函数在另一个文件中定义,用static将函数的链接性设置为内部的。
动态分配
new运算符负责在堆中找到一个满足要求的内存块和指定要使用的位置两种功能。
演示new运算符的四种用法:
#include<new>
struct chaff
{
...
};
char buffer1[50];
char buffer2[500];
int main()
{
chaff *p1, *p2;
int *p3, *p4;
p1 = new chaff; //在堆中找到满足chaff的内存
p3 = new int[20]; //在堆中找到满足数组大小的内存
p2 = new (buffer1) chaff;//将结构放在buffer1中
p4 = new (buffer2) int[20];//将数组放在buffer2中