C 特别关键字 static、extern、const等

来源:互联网 发布:php 批量不重复卡密 编辑:程序博客网 时间:2024/04/30 01:28

========================const========================

------------------------前言------------------------

        常量:(不可以定义结构型常量)常量包括字面常量,符号常量,枚举常量这几种类型;

--字面常量:整形常量,字符型常量,字符串常量。注意: 不存在 数组常量,结构体常量等结构型的 字面常量 。但是存在结构型的符号常量; 

--符号常量:(可以定义结构型常量)用#define和const定义的常量! 

------------------------定义------------------------

--const是一个C语言的关键字,它限定一个变量不允许被改变

--作用:

1.可以定义const常量,具有不可变性。例如:const int Max=100; Max++会产生错误; 

2.便于进行类型检查,使编译器对处理内容有更多了解,消除了一些隐患。例如: void f(const int i) { .........} 编译器就会知道i是一个常量,不允许修改; 

3.可以避免意义模糊的数字出现,同样可以很方便地进行参数的调整和修改。 同宏定义一样,可以做到不变则已,一变都变!如(1)中,如果想修改Max的内容,只需要:const int Max=you want;即可!
4.可以保护被修饰的东西,防止意外的修改,增强程序的健壮性。 还是上面的例子,如果在函数体内修改了i,编译器就会报错;例如: void f(const int i) { i=10;//error! }
5.可以节省空间,避免不必要的内存分配。 例如:

 #define PI 3.14159 //常量宏   const double Pi=3.14159; //此时并未将Pi放入RAM中 ......   double i=Pi; //此时为Pi分配内存,以后不再分配!   double I=PI; //编译期间进行宏替换,分配内存   double j=Pi; //没有内存分配   double J=PI; //再进行宏替换,又一次分配内存! 
         const定义常量从汇编的角度来看,只是给出了对应的内存地址,而不是象#define一样给出的是立即数,所以,const定义的常量在程序运行过程中只有一份拷贝,而#define定义的常量在内存中有若干个拷贝。
6.提高了效率。编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高

------------------------详解------------------------

--const变量&常量

const int n = 5;int a[n];
而ANSI C规定数组定义时长度必须是“常量”,“只读变量”也是不可以的,“常量”不等于“不可变的变量”

--const & 指针

const int nValue;或int const nValue; //nValue是constconst char *pContent; 或char const * pContent;//*pContent是const, pContent可变char* const pContent; //pContent是const,*pContent可变const char* const pContent; 或char const* const pContent; //pContent和*pContent都是const
const只修饰其后的变量,至于const放在类型前还是类型后并没有区别(例子中跟int 和char调换位置),但在指针符号(*)的不同位置时,表示不同类型(指针或变量)

备注:const在*的左边,则指针指向的变量的值不可直接通过指针改变;在*的右边,则指针的指向不可变。简记为“左定值,右定向”,例:

//指针指向的变量的值不能变,指向可变int x = 1; int y = 2;const int* px = &x; // 这两句表达式一样效果 int const* px = &x; px = &y; //正确,允许改变指向*px = 3; //错误,不允许改变指针指向的变量的值//指针指向的变量的值可以改变,指向不可变int x = 1;int y = 2;int* const px = &x;px = &y; //错误,不允许改变指针指向*px = 3; //正确,允许改变指针指向的变量的值

--const怎样限定内容

typedef char * pStr;             //例1const char *p1 =" string"; //1式const pStr p2 =" string"; //2式p1++;// 正确p2++;//错误-------------------------------//例2int const * p1,p2;  //p2是const;(*p1)是一整体,因此(*p1)是const,但p1是可变的int * const p1,p2;  //p1是const,(* const p1)是整体,所以const不修饰p2。
const type m;限定m不可变。例子1比较特殊,可看作type为2式中的pStr,替换后为const pStr m,跟上文中“左定值,右定向”有点矛盾。

------------------------对比------------------------

--const 与define宏定义:

1.编译器处理方式不同:   define宏是在预处理阶段展开;const常量是编译运行阶段使用。
2.类型和安全检查不同:define宏没有类型,不做任何类型检查,仅仅是展开;const常量有具体的类型,在编译阶段会执行类型检查;
3.存储方式不同:define宏仅仅是展开不会分配内存;const常量会在内存中分配;(只是说一般情况)
4.const 可以节省空间
,避免不必要的内存分配。 例如:

#define PI 3.14159 //常量宏 const doulbe Pi=3.14159; //此时并未将Pi放入ROM中 ...... double i=Pi; //此时为Pi分配内存,以后不再分配! double I=PI; //编译期间进行宏替换,分配内存 double j=Pi; //没有内存分配 double J=PI; //再进行宏替换,又一次分配内存!
const定义常量从汇编的角度来看,只是给出了对应的内存地址,而不是象#define一样给出的是立即数,所以,const定义的常量在程序运行过程中只有一份拷贝(因为是全局的只读变量,存在静态区),而 #define定义的常量在内存中有若干个拷贝。
5.宏替换只作替换,不做计算,不做表达式求解;

备注:#define 定义的常量, 除了字符串字面常量外都不占内存 ,所以无法取常量的地址,仅仅是宏替换而已。eg: #define NAME “pang dong” 本质是字符串字面常量,会占用“静态存储区” 。字面常量跟它一个道理(静态存储区/立即数)。

========================static========================

------------------------C中------------------------

1. static修饰函数中的变量(栈变量):改变变量的生存期,作用域不变仍为所在函数。 只被初始化一次。
2. static修饰全局变量:限制全局变量只能被模块内访问,不可以在别的模块中用extern声明调用。
3. static修饰函数:作用与修饰全局变量类似,也是限制该函数只能在模块内访问,不能再别的模块中用extern声明调用。

//文件a.cstatic int i; //只在a文件中用int j;          //在工程里用static void init()         //只在a文件中用{  }void callme()          //在工程中用{    static int sum;}//文件b.cextern int j;                    //调用a文件里的extern void callme();   //调用a文件里的int main(){  ...}
------------------------C++中------------------------
1. static静态数据成员属于整个类所有,类的所有对象共同维护。
2. static静态函数成员也属于整个类,一般用于调用静态数据成员,不能直接访问非static成员(要指定类才行)
class Point{public:  ....  static void show()  { cout << count <<endl;}private:  ...  static int count;    //这里只声明,没有分配内存,没有初始化。           }int Point::count = 0; // 这里初始化静态变量int main(){   Point a(4,5);   Point::show();  //也可以a.show();}
备注:全局变量和全局静态变量的区别:全局变量默认是动态的,作用域是整个工程,在一个文件内定义的全局变量,在另一个文件中,通过extern 全局变量名的声明,就可以使用全局变量。全局静态变量作用域是声明此变量所在的文件,其他的文件即使用extern声明也不能使用。

========================extern========================

       extern可置于变量或者函数前,以表示变量或者函数的定义在别的文件中(声明),提示编译器遇到此变量和函数时在其他模块中寻找其定义。另外,extern也可用来进行链接指定。

------------------------extern变量------------------------

extern int a;//声明一个全局变量aint a; //定义一个全局变量aextern int a =0 ;//定义一个全局变量a 并给初值。一旦给予赋值,一定是定义,定义才会分配存储空间。int a =0;//定义一个全局变量a,并给初值,
备注:

1.声明之后你不能直接使用这个变量,需要定义之后才能使用。
2.第四个等于第三个,都是定义一个可以被外部使用的全局变量,并给初值。
3.定义只能出现在一处。也就是说,不管是int a;还是int a=0;都只能出现一次,而那个extern int a可以出现很多次。
4.当你要引用一个全局变量的时候,你就要声明extern int a;这时候extern不能省略,因为省略了,就变成int a;这是一个定义,不是声明
------------------------extern函数------------------------

      如果函数的声明中带有关键字extern,仅仅是暗示这个函数可能在别的源文件里定义,没有其它作用。即下述两个函数声明没有明显的区别:extern int f(); 和int f();函数定义和声明时extern可有可无

------------------------备注------------------------

1.声明和定义的区别

--函数很好区分;

--变量:定义,用于为变量分配存储空间,还可为变量指定初始值。程序中,变量有且仅有一个定义;声明:用于向程序表明变量的类型和名字。注意下它俩关系:有的仅仅是声明,有的只是定义,有的既是定义也是声明,(可以参见上文extern变量例子);

2.关于全局变量

//A.cppint  i;int main(){ …… }//B.cppint i;
在A.cpp中我们定义了一个全局变量i,在B中我们也定义了一个全局变量i。我们对A和B分别编译,都可以正常通过编译,但是进行链接的时候,却出现了错误。这就是说,在编译阶段,各个文件中定义的全局变量相互是不透明的,编译A时觉察不到B中也定义了i,同样,编译B时觉察不到A中也定义了i。但是到了链接阶段,要将各个文件的内容“合为一体”,因此,如果某些文件中定义的全局变量名相同的话,在这个时候就会出现错误,也就是上面提示的重复定义的错误。因而,定义于某文件内的全局变量,在链接完成后,它的可见范围被扩大到了整个程序

3.关于extern和头文件:要想在本源文件中使用另一个源文件的变量/函数,就需要在使用前用extern声明该变量/函数。至于声明的方式是:可以在m文件中,使用前用extern声明该变量/函数;可以在头文件中用extern声明该变量/函数,也可以#include另一个源文件头文件(该头文件必须包含变量/函数的声明。特别注意变量的声明别跟定义搞混)

4.程序设计风格:

--不要把变量定义放入.h文件,这样容易导致重复定义错误。
--尽量使用static关键字把变量定义限制于该源文件作用域,除非变量被设计成全局的。

--可以在头文件中声明一个变量,在用的时候包含这个头文件就声明了这个变量。


0 0
原创粉丝点击