关键字
register关键字是用来请求编译器尽可能将变量的值保存在CPU内部寄存器中,这样省去了CPU从内存中抓取数据的时间,从而提高程序的运行效率。
尽可能:CPU内部寄存器的内存有限,不可能把所有变量都存放在寄存器中
变量:通常用registr来修饰频繁被访问的变量。
保存在寄存器中:
计算机的三大组成部分,即CPU、硬件和内存。
CPU从内存中抓取数据,内存里面执行的程序最后会保存在硬盘里。
运算器、控制器和存储器是CPU的三大组成部分。
当对一个变量频繁被读写时,需要反复访问内存,从而花费大量的存取时间。为此,C语言提供了一种变量,即寄存器变量。这种变量存放在CPU的寄存器中,使用时,不需要访问内存,而直接从寄存器中读写,从而提高效率。寄存器变量的说明符是register。对于循环次数较多的循环控制变量及循环体内反复使用的变量均可定义为寄存器变量,而循环计数是应用寄存器变量的最好候选者。
使用register关键字的相关注意事项:
(1)register只能修饰局部变量,不能修饰全局变量和函数。因为全局变量可能会被多个进程访问,如果将其保存为register变量,只有当前进程知道全局变量的位置而其他进程不知道。
(2)不能用&(取地址)来获取register修饰的变量的地址。因为该变量保存在寄存器中,取地址后获取的是内存的地址。
(3)register修饰的变量一定是CPU所能接受的数据类型。
static关键字
static关键字即可以修饰变量(包括局部变量和全局变量)也可以修饰函数。
1.static修饰局部变量
在局部变量之前加上关键字static,局部变量就被定义成为一个局部静态变量。
特点如下:
1)存储区:有栈变为静态存储区rw data,生存期为整个源程序,只能在定义该变量的函数内使用。退出该函数后, 尽管该变量还继续存在,但不能使用它;
2)作用域:作用域仍为局部作用域,当定义它的函数或者语句块结束的时候,作用域随之结束。
2.static修饰全局变量
在全局变量前加static,全局变量就被定义成为一个全局静态变量。
特点如下:
1)存储区:静态存储区没变(静态存储区在整个程序运行期间都存在);
2)作用域:全局静态变量在声明他的文件之外是不可见的。准确地讲从定义之处开始到文件结尾。非静态全局变量的作用域是整个源程序(多个源文件可以共同使用); 而静态全局变量则限制了其作用域,即只在定义该变量的源文件内有效,在同一源程序的其它源文件中不能使用它。
好处:
1)不会被其他文件所访问,修改;
2)其他文件中可以使用相同名字的变量,不会发生冲突。
3. static修饰函数
在函数的返回类型前加上关键字static,函数就被定义成为静态函数。
函数的定义和声明默认情况下是extern的,但静态函数只是在声明他的文件当中可见,不能被其他文件所用。只能被本文件中的函数调用,而不能被同一程序其它文件中的函数调用
好处:
1)其他文件中可以定义相同名字的函数,不会发生冲突
2)静态函数不能被其他文件所用。
extern关键字:外部声明,声明变量是在其他文件被定义的。
注意:在声明时需要加上数据类型。extern+数据类型(int等)+变量名(如count);
const关键字:只读变量。
1.const修饰变量时必须要作初始化。
2.使用技巧:
const int *p; //修饰指向的对象,p可变,p指向的对象不可变
int const *p; //修饰指向的对象,p可变,p指向的对象不可变
int * const p; //修饰指针p, p不可变,p指向的对象可变
const int * const p; //指针p和p指向的对象都不可变
通过上面的例子我们可以总结出一句话:“近水楼台先得月!”,这也就是说当关键字const靠近谁,这个变量指向的对象不可变!
3.通常用const来修饰函数的形参,在函数实现过程中避免修改实参的值。
4.总结:const关键字修饰的变量是只读变量,他的空间可变,但是不能通过变量名来修改其空间的值。
typedef关键字:给数据类型重起名字。
优点:
(1)提高代码的可移植性;
(2)方便编程中定义变量,把复杂的变量名简化,提高编程效率;
(3)解释某些变量(注释作用)。
volatile关键字
什么是volatile
volatile总是与优化有关,编译器有一种技术叫做数据流分析,分析程序中的变量在哪里赋值、在哪里使用、在哪里失效,分析结果可以用于常量合并,常量传播等优化,进一步可以死代码消除。但有时这些优化不是程序所需要的,这时可以用volatile关键字禁止做这些优化,volatile的字面含义是易变的。
作用:
1 在多任务、中断、甚至setjmp环境下,变量可能被其他的程序改变,编译器自己无法知道,volatile就是告诉编译器这种情况。
2 不做常量合并、常量传播等优化,
3 对volatile变量的读写不会被优化掉。如果你对一个变量赋值但后面没用到,编译器常常可以省略那个赋值***作,然而对MemoryMapped IO的处理是不能这样优化的。
前面有人说volatile可以保证对内存操作的原子性,这种说法不大准确,其一,x86需要LOCK前缀才能在SMP下保证原子性,其二,RISC根本不能对内存直接运算,要保证原子性得用别的方法,如atomic_inc。何时用:
1、中断服务程序中修改的供其它程序检测的变量需要加volatile;
2、多任务环境下各任务间共享的标志应该加volatile;
3、存储器映射的硬件寄存器通常也要加volatile说明,因为每次对它的读写都可能由不同意义;
另外,以上这几种情况经常还要同时考虑数据的完整性(相互关联的几个标志读了一半被打断了重写),在1中可以通过关中断来实现,2中可以禁止任务调度,3中则只能依靠硬件的良好设计了。