作用域描述了一个程序可以访问一个标识符的一个或多个区域。一个C变量的作用域可以是:文件作用域、块级作用域、函数原形作用域。 函数原形作用域适用于函数原型中的变量名。
int unists = 0;//unists具有文件作用域,更准确的说,它具有外部连接文件作用域
int main(){
}
翻译单元和文件: 你认为的多个文件在编译器中可以以单个文件出现,例如在源代码中包含一个或者多个头文件,头文件会一次包含其他头文件,所以会包含多个独立的物理文件,但是C预处理实际上是用包含的头文件替换#include指令,所以编译器源代码文件和所有的头文件都看成是一个包含信息的单独文件,这个文件被称为翻译单元(translation unit)。描述一个具有文件作用域的变量时,它实际的可见范围是整个翻译单元,如果程序由多个源代码文件组成,那么该程序也将由多个翻译单元组成,每个翻译单元均对应一个源代码文件和它对应的多个包换的文件。
C变量具有三种连接属性:外部链接、内部链接、无链接。
无链接对应的变量作用域:函数作用域、块级作用域、函数原形作用域。
具有文件作用域的变量可以是外部链接或者内部链接:
- 内部链接:只能在一个翻译单元中使用
- 外部链接:可以在多文件程序中使用
int giants = 5;//文件作用域,外部链接,称为内部链接文件作用域,简称文件作用域
static int dodgers = 4;//文件作用域,内部链接,称为外部链接文件作用域,简称全局作用域或程序作用域
int main(){}
C变量具有四种存储时期:
- 静态存储时期,外部链接和内部链接都是静态存储期,如果一个变量是静态存储期的,那么它将在程序运行期间一直存在,全局变量具有的是静态存储时期。
- 自动存储时期,块级作用域的变量一般具有的是自动存储时期,程序进入代码块是,自动为变量分配内存,退出块时,分配的内存将被释放
- 线程存储期:用于并发设计
- 动态分配存储期:使用malloc()申请内存
对于文件作用域变量,关键字static表明的是链接属性,而不是存储期
C使用作用域、链接、存储时期来定义5钟存储类**:自动、寄存器、具有代码块作用域的静态、具有外部链接的静态、具有内部连接的静态。**
存储类别列表:
存储类别 | 存储期 | 作用域 | 链接 | 声明方式 |
---|---|---|---|---|
自动 | 自动 | 块 | 无 | 块内 |
寄存器 | 自动 | 块 | 无 | 块内,register修饰 |
静态外部链接 | 静态 | 文件 | 外部 | 所有函数外 |
静态内部链接 | 静态 | 块 | 内部 | 所有函数外,使用static修饰 |
静态无链接(空连接) | 静态 | 块 | 无 | 块内,使用static修饰 |
多文件: 只有当程序有多个翻译单元组成时,才体现区别内部变量和外部变量的重要性。复杂的C程序通常由多个翻译单元组成, 有时这些文件需要共享一个外部变量,C通过在一个文件中进行定义式声明,然后在其他文件中进行引用式声明来实现共享。
关键字static和extern的含义取决于上下文,C语言有6个关键字作为存储类别声明符:auto、register、extern、static、_Thread_local和typedef(语法原因归于此处)
。
大多数情况下不能同时使用多个存储类别说明符,这位这不能将任一存储类别说明符作为typedef的一部分。唯一列外的是_Thread_local
,它可以和static和extern
一起使用。
- auto说明变量式自动存储期
- register说明符只能用于块作用域的变量,保护了该变量的内存地址不会被获取,但register只是一个请求,并不一定会成功
- static说明符创建的对象具有静态存储期
- extern说明符表明声明的变量定义在别处。
定义和声明:extern用于声明需要用到定义在别处的变量,而不是用来定义变量,不要用extern来定义变量。
上面介绍的五种存储类的共同点是:在决定了使用哪种存储类后,就自动决定了作用域和存储时期,这符合预先指定的 内存管理规则。除了上面介绍的五种存储类之外,还有更灵活的方式来管理内存。及使用库函数来手动管理内存。
函数也有存储类别:
- 外部函数(默认)
- 静态函数
- 内联函数(C99)
double gamma(double);//该函数为外部函数
static doble beta(int,int);//该函数为静态函数
extern double delte(double,int);//用extern来声明定义在其他文件的函数
存储类别选择:优先使用自动存储类别。不要轻易定义共享变量,以防止该变量被篡改,唯一例外的是const数据。因为它们在初始化以后不会被修改。
**定义变量的法则:**按需知道,尽量在函数内部解决所有任务,只共享那些需要共享的变量
通常用类型(比如int)和存储类别(比如auto)来描述一个变量。
- C90新增了两个属性:恒常性和易变性
- 恒常性,对应const关键字,const用于定义常量
- 易变性,对应volatile关键字,告诉编译器该变量处理可以被程序修改外,还可以被其他代理修改
- C99新增了第三个限定符:
restrict
用于提高编译器优化 - C11新增了第四个限定符:
_Atomic