C关键字 register extern const static volatile typedef 逐一浅析

2016-12-01 10:22:07来源:http://blog.csdn.net/guanyasu/article/details/52987943作者:guanyasu人点击

第七城市

register


作用:请求编译器尽可能地将变量存在CPU内部寄存器中,而不是内存寻址访问,省去CPU从内存中抓取数据 的时间,以此提高效率。


使用情况:循环变量、使用频率高的变量


使用register注意


1、修饰变量类型必须是CPU所接受的。


2、因为register变量可能不存放在内存中,所以不能通过“&”来获取register变量的地址。


3、只能修饰局部变量,不能修饰全局变量,因为全局变量可能被多个进程使用(访问),声明为register只有当前进程知道地址。



But!


在某些情况下,把变量保存在寄存器中反而降低了程序运行速度。因为被占用的寄存器不能再用于其他目的。或者变量被使用的次数不够多,不足以装入和存贮变量所带来的额外开销。


Last but not least!


早期的C编译程序不会把变量保存在寄存器中,除非你命令它这样做,这时register修饰符是C语言的一种很有价值的补充。然而,随着编译程序设计技术的进步,在决定那些变量应该被存到寄存器中时,现在的C编译环境能比程序员做出更好的决定。实际上,许多编译程序都会忽略register修饰符,因为尽管它完全合法,但它仅仅是暗示而不是命令。FA**

extern


作用extern可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中提示编译器遇到此变量和函数时在其他模块中寻找其定义


用法注意点


1.如果文件a.c需要引用b.c中变量int v,就可以在a.c中声明extern int v,然后就可以引用变量v。能够被其他模块以extern修饰符引用到的变量通
常是全局变量.详细介绍:点击打开链接

2.如果函数的声明中带有关键字extern,仅仅是暗示这个函数可能在别的源文件里定义,没有其它作用。即下述两个函数声明没有区别:
 extern int f();int f();
3.如果定义函数的c文件在对应的头文件中声明了定义的函数,那么在其他c文件中要使用这些函数,只需要包含这个头文件即可使用。
4.如果你不想包含头文件,那么在.c中声明该函数。一般来说,声明定义在本文件的函数不用“extern”,声明定义在其他文件中的函数 用“extern”


const


作用:如果变量声明中带有关键字const,变量就被强调成只读变量,不能通过赋值、增量或减量运算来修改该变量的值。


使用注意点


1、用const修饰变量,一定要对变量初始化,否则后面就不能初始化了。


2、在指针中使用const,需要区分让指针本身成为const和让指针指向的值成为const区分开来。


①const int *p = &num等同于int const *p = &num,其中p指向的值必须是不变的,但p本身的值可以改变。即(*p)++不可以


②int *const p = &num,其中p要总是指向同一个地址,但所指向的值可以改变。即p++不可以


③const int* const p =&num,意味着p总是指向同一个位置,并且它所指向位置存储的值也是不能改变的。即(*p)++和p++皆不可以


总结:一个位于*左边的任意位置的const使得数据成为常量,而一个位于*右边的const使得指针自身成为常量。可以简单记为const离谁近,谁不 能变。


3、在函数声明时修饰参数,为了保护实参的值,注意一般只修饰函数形式参量的指针。例如,char *strcat(char *ptr,const char *src),表明src指向的数据是不 可变 的,此函数本意是在第一个字符串末尾添加第二个字符串的一份拷贝,这改变了第一个字符串,但不改变第二个字符串,这样声明也体现了这一点。


4、对全局数据使用const。全局变量是危险的,对全局变量使用const限定词是很合理的。全局变量只在本文件中使用,则和以上用法一样。在多个文件中共 享,可以使用两个策略。


①在一个文件中进行定义声明,在其他文件中进行引用声明,使用关键字extern


如/*file1.c*/中 const double PI = 3.14159;


/*file2.c*/中 extern const double PI;


②将常量放在.h文件中声明,但必须加static关键字,其他要使用该常量的.c文件包含此.h文件即可。


如/*constant.h*/中 static const double PI = 3.14159;


/*file1*/中 #include“constant.h”


/*file2*/中#include“constant.h”


5、事实上const修饰变量后我们依然可以通过指针强制类型转换方式修改空间的值。如,


const int a = 3;


int *b = (int *) &a;


*b = 5;


printf("a = %d,*b = %d/n",a,*b);


结果:a = 5,*b = 5


但是这里需要说的是这样修改有时候会带来一些未知情况发生,所以这样修改算是一种奇怪的语法。一名好的工程师,在项目里是绝对不会,也不应该使 用奇怪的语法。推荐两篇博文
点击打开链接博文1博文2



static


三大类用法


1、static全局变量:当一个进程的全局变量被声明为static之后,它的中文名叫静态全局变量。静态全局变量和其他的全局变量的存
储地点并没有区别,都存在数据区中的静态数据区,但是
它只在定义它的源文件内有效,其他源文件无法访问它。static全局 变量只初使化一次,防止在其他文件单元中被引用;利用这一特性可以在不同的文件中定义同名函数和同名变量,而不必担心命
名冲突。
 


2、static局部变量:static局部变量中文名叫静态局部变量它和普通局部变量的区别:


静态局部变量被编译器放在全局存储区.data,所以它虽然是局部的,但是在程序的整个生命周期中存在。


静态局部变量如果没有被用户初始化,则会被编译器自动赋值为0,以后每次调用静态局部变量的时候都用上次调用后的值。


3、static函数:static修饰一个函数,函数只可在本文件中使用。 static函数可以很好地解决不同原文件中函数同名的问题,因为一 个源文件对于其他源文件中的static函数是不可见的。


关于static推荐两篇博文博文1博文2

volatile


作用volatile 影响编译器编译的结果,它指出,volatile 变量是随时可能发生变化的,与volatile变量有关的运算,不要进行编译优化,以免出错。


简单点说就是volite修饰变量后,不管其值有无变化,每次对其值访问时,都会重新从变量的地址里读取,而不是使用保存在寄存器里的备份。


下面是volatile变量的几个例子:
①并行设备的硬件寄存器(如:状态寄存器)
② 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)
③ 多线程应用中被几个任务共享的变量



volatile经常使用在嵌入式开发中,这里推进博文:点击打开链接



typedef



作用:为某一类型创建自己的名字。


使用注意点


1、typedef与#define相似,但它们有三个不同之处:


①与#define不同,typedef给出的符号名称仅限于类型,而不是对值。


②typedef的解释由编译器,而不是预处理器执行。


③虽然它的范围有限,但在其受限范围内,typedef比#define更灵活。


2、定义一种类型的别名,而不只是简单的宏替换。可以用作同时声明指针型的多个对象


char*pa,pb;初学者会认为这就定义了两个字符型指针,其实不是,它只声明了一个指向字符变量的指针,和一个字符型变量。但是用
typedef char *PCHAR;


PCHAR pa,pb;


就能达到效果,而且简答方便,易识别。


3、这些定义通常使用大写字母,以提醒用户这个类型名称实际说上是一个符号缩写。


4、typedef可以增强代码的可移植性。


5、typedef的名称经常被用于复杂的类型


如typedef char(*FRPTC())[5];


6、用typedef并不是创建新的类型,它只是创建了便于使用的标签。


7、易错:



typedef char * string;


const string s;与const char * s不等价


s不是常量指针(指向常量的指针)而是指针常量(指针本身是常量)


因为typedef 的替换并不是完全基于文本(这正是typedef的优点之一)在声明const string s中s被声明为const的原因与const int i将i声明为const的原因一 致,s的声明不会深入到typedef内部来发现指针。


补充:如下定义


#define string char *


const string s; 与const char * s等价;


typedef 就像 auto,extern,mutable,static,和 register 一样,是一个存储类关键字。typedef
声明中不能用 任何其它存储类关键字。


如错误typedef register int FAST_COUNTER;


不能在声明中有多个存储类关键字。因为符号 typedef 已经占据了存储类关键字的位置


推荐博文:点击打开链接





第七城市

最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台