转自:http://jlyq.blog.sohu.com/13781512.html
1.static关键字的作用——限制作用域,可用于修饰局部变量、全局变量和函数
(1)当用static声明函数内的局部变量时,表示这个局部变量是在静态存储区分配的空间,在函数调用结束后其占用的存储单元并不释放,仍然保留原值。此外,静态局部变量是在编译时赋一次初值,程序运行时每次调用函数都不再重新赋初值,而是使用前次函数调用结束时的值。若程序不赋初值,则编译时自动赋值0(普通局部变量不赋初值的话,其值不确定)。
(2)当用static声明在函数体外的全局变量时,表示这个全局变量只能用于本文件,而不能被别的文件引用(即使使用了extern来扩展使用域),这样就能在不同文件中使用相同的全局变量名,提高了程序的通用性和可移植性。//ps:全局变量和静态全局变量都存放在静态存储区中,都是在编译时分配内存,只是作用域不同(全局变量可以在其他文件中用extern扩展使用域)。
(3)当用static声明函数时,表示此函数只能被本文件中的其他函数调用(称为内部函数),这样在不同文件中就可以使用相同函数名,只要用static声明即可。
2.extern关键字的作用
(1)用extern声明全局变量。
a.在一个文件内声明全局变量,可以将全局变量的使用域扩展到从“声明”到文件结尾,而不是从“定义”到文件结尾。
b.在一个文件中用extern声明另一个文件定义的全局变量,可将此全局变量的作用域扩展到这个文件。
ps: 系统处理extern的过程:编译时遇到extern,先在本文件中找是否有此全局变量的定义(即a情况),若没有,则在连接时从其他文件中找此全局变量的定义(b情况)。如果找不到,则出错。
(2)当用extern在定义函数时,表示此函数可以被其他文件的函数调用。//此种情况extern可以省略
(3)当需要使用别的文件的函数时,用extern声明所用的函数是外部函数。
(4)在C++语言中调用C编译器编译的C语言函数,要用extern "C"声明,原因是:C++语言支持函数重载,C语言不支持函数重载。函数被C++编译后在库中的名字与C语言的不同。假设某个函数的原型为:void foo(int x, int y); 该函数被C编译器编译后在库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字。C++提供了C连接交换指定符号extern“C”来解决名字匹配问题
声明与定义:
1.从广义上说,声明包含定义。“int a;”--既是声明也是定义。“extern A;”只是声明不是定义。
2.从狭义上说,建立了存储空间的是定义,不需要建立存储空间的是声明。
3.关键字const的作用——只读不写,可用于定义const常量,修饰函数的输入参数、返回值及函数本身
笼统的说,const的意思是“只能读不能写”。
(1)给读你代码的人传达非常有用的信息。例如,在函数的形参前添加const关键字意味着这个参数在函数体内不会被修改,属于"输入参数"。
(2)合理地使用关键字const可以使编译器很自然地保护那些不希望被改变的参数,防止其被无意的代码修改,这样可以减少bug的出现。
ps:在编译阶段需要的常数仍然只能以#define宏定义!在C语言中如下程序是非法的:
const int SIZE = 10;
char a[SIZE];//编译时SIZE仍是变量,变长数组是不允许的
几个const相关的定义实例:
(1)const int a; = int const a;
const int *p; = int const *p;
const与int前后顺序可以调换,前提是他们是紧挨在一起。
(2)const int * p与int * const p
a.const int * p----const修饰的是*p,即*p不能修改,但p可以修改。
b.int * const p----const修饰的是p,即p指针所指的地址不能改,而地址空间中的值可以修改
(3)int * p指针指向const int i常量的情况
const int i=5;
int *p;
p=&i; //这样是不行的,编译出错。const int 类型的i的地址是不能赋值给指向int类型地址的指针pi的。否则pi岂不是能修改i1的值了吗!
解决办法是只要将他们的类型统一就可以了,如:
const int *p;//将p定义为const int的指针
或者强制类型转换:pi=(int* ) &i;//至于是否可以通过*p来修改i的值,根据编译器不同而不同
(4)用const int * const p声明的指针
int i;
const int * const p=&i;//p的值不能修改,也不能通过*p修改i的值。但可直接修改i的值
注意: const修饰的变量,只能在定义的时候赋初值,不能在新行赋值。
Const修饰只读变量与#define的区别:
const 定义的只读变量从汇编的角度来看,只是给出了对应的内存地址,而不是象#define一样给出的是立即数。
所以,const 定义的只读变量在程序运行过程中只有一份拷贝(因为它是全局的只读变量,存放在静态区),而#define 定义的宏常量在内存中有若干个拷贝。
#define 宏是在预编译阶段进行替换,而const 修饰的只读变量是在编译的时候确定其值。
#define 宏没有类型,而const 修饰的只读变量具有特定的类型。
注意:const变量有全局的和局部的。C语言中全局的const变量默认为外连接,所以默认都是有内存地址的,c++中全局的const变量默认为内连接,它可以被编译器放到符号表中作为编译期常量,所以在C中,const int k = 2; int a[k]是非法的,但在C++中是合法的。而局部的const变量在C和C++中一视同仁,都是放在函数局部栈中的。所以局部的const变量只是用来吓唬人的,想改它的值照样改,修改的时候只要做个强制类型转化就好。至于全局的const变量,C中默认是外连接,它有地址,有地址当然也能够被改掉,所以,你可以像在C语言中改变局部const变量那样通过指针来修改全局const的值,编译时没有任何问题,连个warning都没有,只不过在运行时,你会得到一个segmentation fault而已。为什么呢?因为全局的const变量是存放在只读数据段里的,它比函数局部栈里的const变量高级,它受到只读数据段的权限保护。而你试图修改一个只读数据段中的内容,当然会得到一个运行时错误。
4.关键字volatile的作用
一个定义为volatile的变量是说这个变量可能会被意想不到的改变,也就是说编译器不会去假设这个变量的值。当编译时用到这个变量的时候,优化器必须每次都重新读取这个变量,而不能使用寄存器里的备份。
volatile变量运用的几个例子:
(1)并行设备的硬件寄存器,如状态寄存器。每个设备在任何时刻都有可能会因为状态的变化而修改寄存器。
(2)一个中断服务子程序中访问到的非自动变量。
(3)多线程任务中被几个任务共享的变量。每个线程都有可能去修改这个变量。
5.关键字register的作用
用register定义的变量存在寄存器中,而不存在内存中。
(1)只有局部自动变量和形式参数可以作为寄存器变量。(不能让全局变量占着寄存器不放;register不和static连用)
(2)不能定义任意多个寄存器变量,处理器中寄存器变量是有限的。
6.关键字typedef的作用
声明新的类型来代替已有的类型。
使用方法:1、先按普通定义的方法写出定义体(如:int n[10];);
2、将变量名换成自己指定的类型名(int NUM[10]);
3、在前面加上typedef得到:typedef int NUM[10];
4、可以用心得类型名来定义变量了:NUM n = int n[10]
注意:typedef是在编译的时候处理的,而#define是在预编译的时候处理;