【c语言】关键字存储类型讲解(auto,extern,static,register,const)

渣渣C的学习之路

用最简单的话,让你最快速明白!

C语言中,每一个变量和函数都有2个属性:数据类型和数据的存储类别。C的存储类别有4种:自动的(auto)、静态的(static)、寄存器的(register)、外部的(extern。变量的存储类别对应变量的作用域与生命周期

1.extern

extern外部声明,简单来说:你如果要在a.c中使用b.c的一个变量avg,直接使用是会报错的,这时候我们便需要用

extern int avg; 在a.h中声明avg,这样就可以引用avg了  

当然你要保证avg是一个全局变量,局部变量不能用extern的修饰,且局部变量在运行时才在堆栈部分分配内存。

注意事项:

1.外部声明可以多次,定义只能一次

简单来说就是avg只能定义一次,但是可以有很多外部声明

extern int a;//声明一个全局变量a
int a; //定义一个全局变量a

extern int a =0 ;//定义一个全局变量a 并给初值。
int a =0;//定义一个全局变量a,并给初值,


int a 等于 extern int a,都是定义一个可以被外部使用的全局变量,并给初值。
但是注意定义只能出现在一处。不管是int a;还是extern int a=0;还是int a=0;都只能出现一次,而extern int a,extern a可以出现很多次。

2.用extern声明外部变量时,类型名可写可不写,如"extern int num;"也可以写成"extern num;"。因为它不是定义变量,可以不指定类型,只许写出外部变量名即可

3.变量如果只是用到声明,放在.h中就行了;
如果声明的同时并定义一个全局变量的话,在.h里用extern声明,并在对应的.c里定义。
其它的.c文件直接include“xx.h”就行了  

// ---- Math.h ----
extern "C";
// ---- Math.C ----
int “C”;

// ---- Add.c ----
#include "Math.h"

C=5;
// C 可以从被调用

这样子是不是很方便!

2.auto   

auto被解释为一个自动存储变量的关键字,也就是申明一块临时的变量内存。函数中的形参和在函数中定义的局部变量(包括符合语句中的局部变量)都属于此类。如 函数中定义变量 int a; 和 auto int a; 是等价的,关键字“auto”是默认省略的,此关键字很少使用

注意事项:

1.auto是定义局部变量,即只能在定义的范围内使用(一般就是在花括号里{})全局变量默认说明符为extern。

2.auto变量在离开作用域是会变程序自动释放,不会发生内存溢出情况(除了包含指针的类)使用auto变量的优势是不需要考虑去变量是否被释放,比较安全。(局部变量)

3.auto不能作为函数的参数

4. auto不能直接用来声明数组

3.static

这个关键字很重要,我们需要对他很了解 

我们分为几点来介绍他

1.

我们知道局部变量在调用完之后就会销毁,而我们有时希望函数中的局部变量的值在函数调用结束后不消失而继续保留原值,即其占用的存储单元不释放,在下一次再调用该函数时,该变量已有值(就是上一次函数调用结束时的值)。这时就应该指定该局部变量为“静态局部变量”,用关键字static进行声明。

2.static在修饰全局变量时,该变量只能在当前文件中使用,其他文件无法访问和使用,即时用extern声明也是无效的,但是可以在多个文件中定义同一个名字的变量,不会受到影响

静态函数只能在声明它的文件中可见,其他文件不能引用该函数

不同的文件可以使用相同名字的静态函数,互不影响

static避免多个文件使用了相同的变量名而导致冲突,

 比如有多个文件,分别由几个人独立开发的。假定他们在各自的文件中定义相同的“全局”变量名(仅仅指在他们独自的文件中全局),当系统集成时,由于他们使用了名字一样的“全局”变量,导致有难于遇见的问题。解决这个问题方便的做法就是在各自文件中,在相同的全局变量申明前加上static修饰符。这样系统就会为他们分配不同的内存,互不影响了。

3.static修饰一个函数,则这个函数同样只能在本文件中调用,不能被其他文件调用

4.Static修饰的局部变量存放在全局数据区的静态变量区。初始化的时候自动初始化为0; 并且在程序执行期间不销毁,程序执行完成之后才销毁(在静态存储区,内存中所有字节默认都是0x00)

下面是中兴通讯2012校招笔试题的一道问答题:

1. static全局变量与普通的全局变量有什么区别 ?

  全局变量(外部变量)的说明之前再冠以static 就构成了静态的全局变量。

  全局变量本身就是静态存储方式, 静态全局变量当然也是静态存储方式。 这两者在存储方式上并无不同。

  这两者的区别在于非静态全局变量的作用域是整个源程序, 当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。 而静态全局变量则限制了其作用域, 即只在定义该变量的源文件内有效, 在同一源程序的其它源文件中不能使用它。由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数公用,因此可以避免在其它源文件中引起错误。

  static全局变量只初使化一次,防止在其他文件单元中被引用;  

2.  static局部变量和普通局部变量有什么区别 ?

   把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。把全局变量改变为静态变量后是改变了它的作用域,限制了它的使用范围。 

  static局部变量只被初始化一次,下一次依据上一次结果值;  

3.  static函数与普通函数有什么区别?

   static函数与普通函数作用域不同,仅在本文件。只在当前源文件中使用的函数应该说明为内部函数(static修饰的函数),内部函数应该在当前源文件中说明和定义。对于可在当前源文件以外使用的函数,应该在一个头文件中说明,要使用这些函数的源文件要包含这个头文件.
 

4.register

register变量表示将变量存储在CPU内部寄存器中,而不是单纯地寻址访问,这样可以提高运算速度和效率,

那么有的同学可能要问,为什么寄存器比寻址访问要快呢?我们首先要知道,CPU是不会直接和内存打交道的,他是会通过寄存器跟内存打交道,数据从内存里拿出来先放到寄存器,然后CPU 再从寄存器里读取数据来处理,处理完后同样把数据通过寄存器存放到内存里,

 寄存器内存阶层中的最顶端

简单来说习大大要处理政务了,那么他是会从各个国家部部长哪里获取信息吧,而不是直接问每个县的县长或者村长获取信息,那么这里CPU就是习大大,通过寄存器(各个国家部门部长),来对内存进行寻址访问(各个地方的各种事务),

正是有着各种各样各自功能的寄存器(很多部门),负责着不同的工作处理,然后汇报给CPU(习大大),这样程序才能正常进行(国家才能正常运转),  这样我们可以知道,寄存器其实就是一块一块小的存储空间,只不过其存取速度要比内存快得多。进水楼台先得月嘛,它离CPU 很近,所以寄存器变量(国家大事),也就是要优先处理啦。

注意事项:

1.register只是请求寄存器变量,不一定能够成功

我们知道寄存器是有限的(各个部门),如果定义了很多register变量,可能会超过CPU的寄存器个数,超过容量,(各个部门政务超负载了)
这时候就没有办法都变为寄存器变量了,这个数量主要看机器性能决定

2.register变量必须是能被CPU所接受的类型。

这通常意味着register变量必须是一个单个的值,并且长度应该小于或者等于整型的长度。不过,有些机器的寄存器也能存放浮点数。  (这个我们很容易理解,不是什么事都能作为国家大事的)

3.因为register变量可能不存放在内存中,所以不能用“&”来获取register变量的地址。

4.用register修饰的变量只能是局部变量,不能是全局变量。CPU的寄存器资源有限,因此不可能让一个变量一直占着CPU寄存器       (领导人不可能一直只处理一件事情)

5.register修饰符暗示编译程序相应的变量将被频繁地使用,如果可能的话,应将其保存在CPU的寄存器中,所以请注意,.register仅仅是暗示而不是命令。      这就好比寄存器(部长)可以说明这件事比较重要,但是不能直接命令CPU(领导人)去做一件事

6.局部静态变量不能定义为寄存器变量。不能写成:register static int a, b, c;

虽然它被称作最近快的变量,但是也是比较不安全的变量,现在使用不多

5.const

我对这个关键字一直抱有敬畏之心,因为之前看过一位某国企面试官对面试者提问const时的博客,就一直感觉很有文章

简单来说:我们在写程序时,如果需要让一个变量保持不变,不能被修改,那就用const来修饰

const 是 constant 的缩写,意思是“恒定不变的”!

以下两种定义是相同的

const int a = 6;
int const a = 6;

用 const 定义的变量的值是不允许改变的,即不允许给它重新赋值,即使是赋相同的值也不可以,所以在定义常量的时候要先给他初始化(赋值)  ,后面任何修改的操作都是错误的

const和指针


int main()
{
    const int a;
    int const b;
    const char *c;
    char *const d;
    const char * const e;
    return 0;
}

看上面代码, a和b是相同的  

对于c来说 const在*左边 表示c所指向的内存地址不可改变,即c只能指向一个固定地址,但是地址中的值是可以修改的

对于d来说,指针是只读的,也就是 d 本身的值不能被修改,但是它所指向的内存空间是可以被修改的。

对于e来说,不能做任何修改,

常量:固定值

变量:可以变化的量

我们知道,数组的长度不能是变量。虽然 const 定义的是只读变量,就相当于是定义一个常量。但是只读变量也是变量,所以 const 定义的变量仍然不能作为数组的长度

请注意只读这两个字,可以说是精华所在

能力提升:

用 const 修饰的变量,无论是全局变量还是局部变量,生存周期都是程序运行的整个过程。全局变量的生存周期为程序运行的整个过程这个是理所当然的。而使用 const 修饰过的局部变量就有了静态特性,它的生存周期也是程序运行的整个过程。我们知道全局变量是静态的,静态的生存周期就是程序运行的整个过程。但是用const修饰过的局部变量只是有了静态特性,并没有说它变成了静态变量。

我们知道,局部变量存储在栈中,静态变量存储在静态存储区中,而经过 const 修饰过的变量存储在内存中的“只读数据段”中。只读数据段中存放着常量和只读变量等不可修改的量。

 有兴趣同学可以参考  《单片机的内存分配》 

来学习一下

都看到这儿了,点个赞再走呗!

发布了60 篇原创文章 · 获赞 815 · 访问量 15万+

猜你喜欢

转载自blog.csdn.net/as480133937/article/details/88539716