关键字
①register
(1)register的作用:
register请求编译器尽可能地让变量的值保存到CPU的内部寄存器中,从而省去CPU从内存中捕获数据的时间,提高程序的运行效率。
*注释:尽可能是因为CPU中的寄存器资源有限,不能让过多的变量都存储到寄存器中。
(2)何时使用register关键字
当我们频繁使用某一个变量时我们可以将该变量定义为register。
(以下是一个草图,画图不是多熟练)
(3)register使用的注意事项
1.register修饰的变量的类型必须是CPU内部寄存器中。
2.register变量可能不是内存中存储,所以不能使用&来获取变量的地址(并且变量保存在寄存器中,取地址获取的是内存的地址)。
3.register只能修饰局部变量,不能修饰全局变量(全局变量会被多个任务,进程访问)。
②static
(1)static的作用:
static可以修饰局部变量、全局变量和函数。
staic修饰的变量全部保存在数据区的静态数据区,没有初始化时,系统默认为0.
1.static修饰局部变量时,该变量成为静态局部变量。
作用:延长局部变量周期,直至程序结束释放。
2.static修饰全局变量时,只能在本文件可见。
3.static修饰函数时,只能在本文件调用
(2)何时使用static关键字
1.当想使局部变量在本函数中使用后不被释放且只在该函数内可见时用static修饰该变量。
(定义全局变量危险,使用时不安全,被其他文件访问,修改等。用staic 可重名,限定了作用域。)
2.当想使某文件中的全局变量不被其它文件所访问时可以使用static修饰该变量。这可以防止其他文件对该全局变量进行操作。
③extern
(1)extern的作用:
用于外部声明引用,声明的变量是在外部文件中定义的。
(2)extern的注意事项:
1.使用extern声明外部变量时要加上该变量的数据类型,语句末尾不能省去“;”,例如:extern int a; 。
2.extern只能声明全局变量。
④const
(1)const的作用:
const用于修饰变量,被修饰的变量为只读变量。
(2)const的注意点:
1.使用const修饰变量时一定注意要初始化。
2.const修饰的变量对应的空间的值可以修改,但不能通过变量名进行修改对应空间的值。
例如:const int a = 5; a = 6; 。
3.在函数的形参中使用const可避免函数对实参的值进行修改,便于调试。
⑤typedef
(1)typedef的作用:
用来为复杂的声明定义简单的别名(与宏定义有差异)
(2)使用typedef的优点
1.提高了代码的移植性
2.把复杂的声明定义为简单的别名,从而提高了编码效率。
3.对变量起到注释的作用,方便其他人阅读代码。
⑥volatile
(1)简介:
volatile是易变的,不稳定的意思,volatile是关键字,是一种类型修饰符,用它修饰的变量表示可以被某些编译器未知的因素更改,比如操作系统、硬件或者其他线程等,遇到这个关键字声明的变量,编译器对访问该变量的代码不在进行优化,从而可以提供对特殊地址的稳定访问。
volatile 关键字告诉编译器该变量是随时可能发生变化的,每次使用它的时候必须从内存中取出他的值,因而编译器生成的汇编代码会从原内存地址中读取数据使用。
如果一个寄存器或者变量表示一个端口或者多个线程的共享数据,就容易出错,所以volatile可以保证对特殊地址的稳定访问。
(2)volatile的深度理解和深入应用场景
volatile总是与优化有关,编译器有一种技术叫做数据流分析,分析程序中的变量在哪里赋值、在哪里使用、在哪里失效,分析结果可以用于常量合并,常量传播等优化,进一步可以死代码消除。但有时这些优化不是程序所需要的,这时可以用volatile关键字禁止做这些优化,volatile的字面含义是易变的,它有下面的作用:
1 不会在两个操作之间把volatile变量缓存在寄存器中。在多任务、中断、甚至setjmp环境下,变量可能被其他的程序改变,编译器 自己无法知道,volatile就是告诉编译器这种情况。
2 不做常量合并、常量传播等优化,所以像下面的代码:
volatile int i = 1;
if (i > 0) ...
if的条件不会当作无条件真。
3 对volatile变量的读写不会被优化掉。如果你对一个变量赋值但后面没用到,编译器常常可以省略那个赋值操作,然而对Memory Mapped IO的处理是不能这样优化的。
应用场景
1、中断服务程序中修改的供其它程序检测的变量需要加volatile;
2、多任务环境下各任务间共享的标志应该加volatile;
3、存储器映射的硬件寄存器通常也要加volatile说明,因为每次对它的读写都可能由不同意义
⑦inline
介绍:函数冠以inline后为内联函数,内联函数是代码被插入到调用者代码处的函数。如同 #define 宏(但并不等同,原因见下文),内联函数通过避免被调用的开销来提高执行效率,尤其是它能够通过调用(“过程化集成”)被编译器优化。
注意点:
当我们过度使用inline函数,会造成程序文件变大,性能降低。程序文件变大是肯定的,但为什么性能会降低呢,inline不是为了提高性能吗?使 用的方式不正确性能不能提高,反而会下降。现在的CPU上都有cache,紧凑的代码在chache中保存的时间更长,这样cache命中的机会更高。
如果某个A函数未定义为inline,并且被很多其它函数调用,那个这个A函数很大的可能会长期被保存在cahe中,这样CPU对代码的执行速度会提高很 多。如果A函数被定义为了inline函数,代码分散各个调用函数中,这样每次指定都不命中都需要去内存把代码拷贝到cache中,然后执行,造成很大的 抖动。
更深一层的理解,当函数整个函数编译为的汇编代码,函数调用的上下文切换占用了大多的时间的时候,可以考虑把此函数定义为inline函数。