概述
C语言变量四大属性:存储类、作用域、生命周期、链接属性。从这四个方面来理解变量相互之间是独立,对程序员编程没有太大的意义。但是将它们连起来看就会对变量有更深的理解。本文章结合这四大属性来看看存储类相关的关键字修饰之后的变量。
注:了解C语言变量四大属性的概念以及相关细节可看C语言基础篇 —— 5.0 详解C语言变量的四大属性
存储类相关的关键字对比表
关键字 | 作用 | 存储类 | 作用域 | 生命周期 | 链接属性 | 说明 |
---|---|---|---|---|---|---|
auto | auto关键字在C语言中只有一个作用修饰局部变量 | 分配在栈上 | 代码块作用域 | 临时生命周期 | 无链接 | 1、auto修饰布局变量,表示这个局部变量是自动局部变量,自动局部变量分配在栈上。 2、平时定义局部变量是就是定义的auto的,只是省略auto关键字而已。auto的局部变量其实就是默认定义的普通局部变量。 3、定义时如果未显示初始化则其值为随机的,变量地址由运行时在栈上分配得到,多次执行时地址不一定相同,函数不能返回该变量的地址(指针)做返回值。 |
static | 第一种用法:用来修饰局部变量,形成静态局部变量。 | 分配在数据段/bss段(显示初始化为非0则在数据段,显示初始化为0或未显示初始化则在bss段) | 代码块作用域 | 永久生命周期 | 无链接 | 1、静态局部变量和非静态局部变量的区别本质上是在存储类不同。 (非静态局部变量分配在栈上;静态局部变量分配在数据段/bss段上。) 2、定义时如果未显示初始化则值为0,变量地址由运行时环境在加载程序时确定,整个程序运行过程中唯一不变;静态局部变量其实就是作用域为代码块作用域(同时链接属性为无链接)的全局变量。静态局部变量可以改用全局变量实现。 |
第二种用法:用来修饰全局变量,形成静态全局变量。 | 分配在数据段/bss段(显示初始化为非0则在数据段,显示初始化为0或未显示初始化则在bss段) | 文件作用域 | 永久生命周期 | 内部链接 | 静态全局变量和非静态全局变量区别在链接属性上不同。 | |
register | register修饰的变量,编译器会尽量将它分配在寄存器中(一般变量都是在内存中)。分配在寄存器中一样的用,但是读写效率会高很多。大幅度提升程序运行效率。 | 寄存器区域 | 文件作用域 | 永久生命周期 | 外链接 | register编译器只能承诺尽量将register修饰的变量放在寄存器中,但是不保证一定放在寄存器中。主要原因是因为寄存器数量有限,不一定使用到。 |
extern | extern主要用来申明全局变量,声明的目的主要是在a.c中定义全局变量而在b.c中使用这个变量。 | 分配在数据段/bss段(显示初始化为非0则在数据段,显示初始化为0或未显示初始化则在bss段) | 文件作用域 | 永久生命周期 | 外链接 | C语言中程序的编译时以单个.c源文件为单位的,因此编译a.c时只考虑a.c中的内容,这就导致a.c中使用了b.c中定义的变量时报错。解决方案是声明(在a.c中用extern声明要使用其他文件的变量,在编译时告诉编译器这个变量在其他文件中有定义) |
volatile | C语言中volatile用来修饰一个变量,表示这个变量可以被编译器之外的东西改变。编译器之内的意思是变量的改变是代码的作用,编译器之外的改变是这个改变不是代码造成的,或者不是当前代码造成的,编译器在编译当前代码时无法预知。 | 分配在数据段/bss段(显示初始化为非0则在数据段,显示初始化为0或未显示初始化则在bss段) | 文件作用域 | 永久生命周期 | 外链接 | 1、编译器在编译当前代码时无法预知的情况有:(1)中断isr中引用的变量(2)多线程中共用的变量(3)硬件会改变的变量 , 这三种情况下改变这个变量的值属于(可变的、易变的)情况。 2、编译器在遇到volatile的时候就不会对这个变量的访问进行优化。编译器的优化在一般情况下是非常好的,可以帮助提升程序效率。但是在特殊情况(volatile)下,变量会被编译器想象之外的力量改变的,这时编译器没有意识到而去优化就会优化出错。 |