static静态变量和函数,extern变量和函数,const变量和函数

一、static静态变量       

       静态变量的类型说明符是static。 静态变量当然是属于静态存储方式,但是属于静态存储方式的量不一定就是静态变量, 例如外部变量虽属于静态存储方式,但不一定是静态变量,必须由 static加以定义后才能成为静态外部变量,或称静态全局变量。 对于自动变量,它属于动态存储方式。 但是也可以用static定义它为静态自动变量,或称静态局部变量,从而成为静态存储方式。
由此看来, 一个变量可由static进行再说明,并改变其原有的存储方式。
1. 静态局部变量
  在局部变量的说明前再加上static说明符就构成静态局部变量。
  例如:
       static int a,b;
       static float array[5]={1,2,3,4,5};
  静态局部变量属于静态存储方式,它具有以下特点:
  (1)静态局部变量在函数内定义,但不象自动变量那样,当调用时就存在,退出函数时就消失。静态局部变量始终存在着,也就是说它的生存期为整个源程序。
  (2)静态局部变量的生存期虽然为整个源程序,但是其作用域仍与自动变量相同,即只能在定义该变量的函数内使用该变量。退出该函数后, 尽管该变量还继续存在,但不能使用它。
  (3)允许对构造类静态局部量赋初值。若未赋以初值,则由系统自动赋以0值。
  (4)对基本类型的静态局部变量若在说明时未赋以初值,则系统自动赋予0值。而对自动变量不赋初值,则其值是不定的。 根据静态局部变量的特点, 可以看出它是一种生存期为整个源程序的量。虽然离开定义它的函数后不能使用,但如再次调用定义它的函数时,它又可继续使用, 而且保存了前次被调用后留下的值。 因此,当多次调用一个函数且要求在调用之间保留某些变量的值时,可考虑采用静态局部变量。虽然用全局变量也可以达到上述目的,但全局变量有时会造成意外的副作用,因此仍以采用局部静态变量为宜
2.静态全局变量
  全局变量(外部变量)的说明之前再冠以static 就构成了静态的全局变量。全局变量本身就是静态存储方式, 静态全局变量当然也是静态存储方式。 这两者在存储方式上并无不同。这两者的区别虽在于非静态全局变量的作用域是整个源程序, 当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。 而静态全局变量则限制了其作用域, 即只在定义该变量的源文件内有效, 在同一源程序的其它源文件中不能使用它。由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数公用, 因此可以避免在其它源文件中引起错误。从以上分析可以看出, 把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。把全局变量改变为静态变量后是改变了它的作用域, 限制了它的使用范围。因此static 这个说明符在不同的地方所起的作用是不同的。应予以注意。

二、static静态函数

        用static修饰的函数,本限定在本源码文件中,不能被本源码文件以外的代码文件调用。而普通的函数,默认是extern的,也就是说,可以被其它代码文件调用该函数。
  在函数的返回类型前加上关键字static,函数就被定义成为静态函数。普通 函数的定义和声明默认情况下是extern的,但静态函数只是在声明他的文件当中可见,不能被其他文件所用。因此定义静态函数有以下好处:
  <1> 其他文件中可以定义相同名字的函数,不会发生冲突。
  <2> 静态函数不能被其他文件所用。

三、extern变量和函数

      如果函数的声明中带有关键字extern,仅仅是暗示这个函数可能在别的源文件里定义,没有其它作用。

 

extern 和 static

 

 (1) extern 表明该变量在别的地方已经定义过了,在这里要使用那个变量.
 (2) static 表示静态的变量,分配内存的时候, 存储在静态区,不存储在栈上面.

 

       static 作用范围是内部连接的关系, 和extern有点相反.它和对象本身是分开存储的,extern也是分开存储的,但是extern可以被其他的对象用extern 引用,而static 不可以,只允许对象本身用它. 具体差别首先,static与extern是一对“水火不容”的家伙,也就是说extern和static不能同时修饰一个变量;其次,static修饰的全局变量声明与定义同时进行,也就是说当你在头文件中使用static声明了全局变量后,它也同时被定义了;最后,static修饰全局变量的作用域只能是本身的编译单元,也就是说它的“全局”只对本编译单元有效,其他编译单元则看不到它。

四、const变量

 

const类型变量
--------------------------------------
int i;
const int *p;
--------------------------------------
int i;
int *const p = &i;
--------------------------------------
int i;
const int *const p = &i;

 

三者有何区别

 

指向常量的指针 和 指针常量

 

const int *p;  //定义一个指向常量的指针。

 

int *const p;  //定义一个指针常量,一旦指向某一变量的地址后,不可再指向其他变量的地址。(注意:指针常量也叫常量指针

 

二者区别:
const int *p; //p是一个变量,但指向一个常量。(即p可以指向任何地址,但是只能通过*p来读这块地址的内容,不能通过*p来写这块地址的内容)

 

int *const p; //p是一个常量,但指向一个变量或者常量。(即如果一旦p指向了任何一个有效的地址后,就不可再指向其他变量的地址,但可以通过*p来读写这块地址的内容)

 


1. const int *p;
const用来修饰int *,*p的内容不可变。

 1 linux下示例代码如下:
 2 
 3 #include <stdio.h>
 4 
 5 int main01()
 6 {
 7     int a = 0;
 8     int *p = &a;        //此时的p指向了一个int类型的地址,可以通过*p的方式来修改这个内存a的值。
 9     *p = 10;
10     printf("a = %d\n", *p); //或者printf("a = %d\n", a);    //此时的*p可读可写。
11 
12     return 0;
13 }
14 
15 int main()
16 {
17     int a = 0;
18     const int *p = &a;  //此时的p指向了一个int类型的地址,但不可以通过*p的方式来修改这个内存a的值。
19     //*p = 10;
20     a = 10;             //但是呢,不可以通过*p来改a的值,可以通过a去修改a的值。
21     printf("a = %d\n", *p); //或者printf("a = %d\n", a);    //此时的*p可读不可写。
22 
23     //c语言的一个小漏洞
24     const int b = 100;
25     //b = 0;    //定义了一个常量,那么这个常量权限是只读了。
26 
27     //通过指针的方法:即可以通过指向一个变量地址的指针去指向它,然后通过*p1去间接的修改b的值。
28     //注意编译的时候会出现警告!我们忽略这个警告强行改!这时把b的值改了!!!
29     //warning: assignment discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
30     //警告:赋值时从指针目标类型丢弃“const”限定符[-Wdiscarded-qualifiers]
31 
32     //这就是在c语言中用常量的时候不用const了!
33     //因为c语言中的const是有问题的,因为可以通过指针变量间接的修改const定义的常量的值,所以在c语言中用#define定义常量的时候更多。
34 
35     //为什么#define不能改呢?实质上#define就是一个文本替换,直接把它替换成一个整数了,整数是一个常量,又不是一个变量。
36     //但是在C++中就没有这个漏洞了。为什么呢?因为c++里面的const是个真的const,而c语言中的const只是在语法的角度不让你去赋值,实际上是假的。
37     //这是c语言本身存在的弱项。
38 
39     int *p1;
40     p1 = &b;    //为了避免这个warning,使用强转即可:p1 = (int *)&b;
41     *p1 = 0;
42     printf("b = %d\n", b);  //或者printf("b = %d\n", *p);
43 
44     int *const p2 = &a;    //表示p2指向了a的地址,而且p2只能指向a的地址,不可再指向其他变量的地址。
45     //p2 = &b;//直接编译错误//p2是一个常量指针,p2只能指向固定的一个变量的地址,但可以用*p2读写这个变量的值。
46 
47     return 0;
48 }

2. int *const p = &i;
const用来修饰p,p是一个常量指针,p只能指向固定的一个变量的地址,但可以用*p读写这个变量的值。

指针p的地址不可变。即表示p指向了i的地址,而且p只能指向i的地址,不可再指向其他变量的地址。

int i = 0;
int j = 0;
int *const p = &i;
p = &j;    //错误
i = 1;    //正确
*p = 1;    //正确

3.const int *const p = &i;

同时限制了指针指向的内容和指向的地址。

转自:https://www.cnblogs.com/chenmingjun/p/8150857.html

 

posted @ 2022-02-16 11:12  量子与太极  阅读(440)  评论(0编辑  收藏  举报