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