作用域和持续性
C++中持续性表示变量在程序运行的过程中什么时候被创建和销毁,作用域表示表示变量可以从哪里被访问到。
持续性
C++中有四种不同持续性的变量:
- 自动存储持续性:例如在代码块中定义的变量,随着初始化语句的执行而创建,随着代码块的结束而销毁。
- 静态存储持续性:在代码块中用
static
关键字修饰的变量和在代码块外声明的变量。它们在编译的时候被初始化,在程序退出的时候才销毁。 - 线程存储持续性:使用
thread_local
声明的变量,线程退出的时候销毁。 - 动态存储持续性:使用
new
运算符创建的变量,只能由delete
释放或者等到程序退出的时候销毁。
作用域
C++中还有三种作用域:
- 本地作用域:在本地代码块中定义的变量,这些变量只能在本地代码块中被访问到。
- 文件作用域:在代码块外声明,并用
static
或const
(用const
修饰的变量作用域默认是文件内,如果需要改成全局,可以使用extern
关键字修饰)修饰的变量,只能在本文件中被访问呢到。 - 全局作用域:在代码块外声明,没有
static
或用extern
修饰的变量,在整个程序中的任何位置都能被访问到(只要不被覆盖)。
声明格式
一个变量的属性由作用域和持续性两个方面描述,由此可以总结出一个表格,来描述不同作用域和持续性的变量的声明格式。假设我们要声明一个int
类型的变量,这里不讨论线程存储持续性
,表中的值表示变量声明的位置/格式
:
持续性/作用域 | 本地 | 文件内 | 全局 |
---|---|---|---|
自动 | 代码块内/int | / | / |
静态 | 代码块内/int | 代码块外/static int | 代码块外/int |
动态 | 任意位置/new | 任意位置/new | 任意位置/new |
更详细的规则
上述表格只是对变量声明格式的一个基本的总结,如果要完全管理变量的持续性和作用域还需要知道一些详细的规则:
- 静态持续性的变量在编译阶段就会被创建,单独放在一块内存中。如果声明的时候没有被初始化,就会被
初始化为零
,并且整个程序运行的过程中只会初始化这一次
。后续程序多次运行到代码块中初始化静态变量的语句时,会跳过该语句。 - 在
C++11
中,register
提示编译器将变量放入寄存器的功能消失了,因为随着编译器的发展,它能自己决定是否将其放入寄存器。后来这个关键字演变成了显式表示变量是自动存储持续性的
。 - 如果想在本文件中访问到其他文件的变量需要在本文件中声明要访问的变量并用
extern
修饰。注意这里只是声明,而不能初始化
。如果用extern
修饰之后还进行了初始化,则该extern
将会失去效果,其结果跟不加extern
效果一样(声明并初始化一个全局静态变量)。 volatile
修饰的变量表示该变量即使程序不对其进行修改,它的值仍可能发生变化。比如一个代表硬件接口的变量,或者系统时钟。mutable
用于修饰结构体中的变量,表示尽管结构体被声明成const
,仍然可以修改该变量的值。- 当一个外部变量(在代码块外声明的变量)被
const
修饰时,其作用域会由全局变成文件内,如果需要将其重新变成全局作用域,可以使用extern
修饰。 - 函数的作用域默认为全局,但是可以使用
static
将其作用域变成文件内。
下面的代码详细展示了上述规则:
//file1.cpp
#include <cstdio>
int global_x = 1; //全局作用域,静态持续性
extern int ex_global_x = 1; //使用了extern还初始化,extern失去作用,变量类型与上一行一样
const int inner_const_x = 1; //用const修饰的全局变量的作用域会变成文件内,file2.cpp中不能访问该变量
const extern int outter_const_x = 1;//使用extern强行将变量的作用域改成全局
static int inner_static_x = 1; //文件内作用域,静态持续性
//函数的默认作用域为全局,file2.cpp中可以访问
void test_for_static(){
static int st_inner_x = 1;//作用域为本地,静态持续性变量。
st_inner_x++;
//每次调用函数后st_inner_x都会+1,而不是一直是2
//因为静态变量的初始化语句只会在编译的时候执行一次,之后每次遇到都会被跳过
printf("Now the static value is: %d\n", st_inner_x);
}
//作用域为文件内的函数,不能再file2.cpp中访问
static void inner_function(){
printf("This is a inner function.\n");
}
int main(void){
int auto_x = 1;//最普通的本地变量
for(int i = 0; i < 3; i++){
test_for_static();
}
}
//file2.cpp
extern int global_x; //表示该变量在其他文件中已经被定义
//如果不用extern int ex_global_x;声明,则不能使用该变量