• C语言中volatile/register/const/static/extern/auto关键字的作用


    目录

    一、volatile

    二、register详解

    三、const详解

    四、static详解

    五、extern详解

    语法

    作用

    六、auto详解


    突然想总结一下这些关键字的作用,灵活使用这些对程序的可靠性和速率都有提高

    一、volatile

    volatile是防止编译器优化,如果是高频繁的变量编译器会自动将变量放到寄存器中,但是有的变量需要实时更新不能间断,放到寄存器中会隔一段时间再去获取变量,导致变量的值不在准确。一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。

    volatile的本意是“易变的” 因为访问寄存器要比访问内存单元快的多,所以编译器一般都会作减少存取内存的优化,但有可能会读脏数据。当要求使用volatile声明变量值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。精确地说就是,遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问;如果不使用valatile,则编译器将对所声明的语句进行优化。(简洁的说就是:volatile关键词影响编译器编译的结果,用volatile声明的变量表示该变量随时可能发生变化,与该变量有关的运算,不要进行编译优化,以免出错

    下面是使用volatile变量的几个场景:

    1>中断服务程序中修改的供其它程序检测的变量需要加volatile;

    2>多任务环境下各任务间共享的标志应该加volatile;

    3>存储器映射的硬件寄存器通常也要加voliate,因为每次对它的读写都可能有不同意义。

    eg: volatile  int *output=(volatile unsigned int *)0xff800000;//定义一个I/O端口

    二、register详解

    寄存器变量就是把使用高频繁的一个变量 系统会将内存中高频繁的变量放入到寄存器中。

    作用:用register关键字修饰变量,就是编译程序时希望把该变量放到寄存器中,这样可以提高对该变量的访问速度。由前言可知,CPU访问寄存器的速度是高于访问内存的速度

    下面是使用register变量的场景和注意事项:

    • 适用于不需要经常修改,但是会被频繁访问的变量,这样可以一定程度上提高访问效率。
    • 变量需要写入寄存器而不在内存中,所以利用&取址运算符是无法获取地址的,即,&取址运算符不能用于register修饰的变量。
    • register变量必须是能被CPU所接受的类型。变量保存在寄存器中,那表示变量的程度不能超过寄存器的位数并且类型要和寄存器接受的数据类型一致。通常情况register修饰的变量必须是一个单个的值,并且长度应该小于或者等于整型的长度。如果寄存器允许存放浮点数,那register修饰的变量也可以是浮点数。
    • 局部静态变量不能定义为寄存器变量。不能写成:register static int a, b, c。我猜测原因是:静态变量的生命周期和整个程序的生命周期是一样的,总不能分配一个寄存器一直被一个变量占用,寄存器资源是很宝贵的,这样太浪费。一般都是用来修饰局部变量
    • 不能定义任意多个寄存器变量,原因很简单Soc的寄存器太少了。就算你用register修饰都不一定会放在寄存器中,更别说还要定义多个。

    三、const详解

    被const修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性。它可以修饰函数的参数、返回值,甚至函数的定义体。

    (1)可以定义常量

    const int a=100;

    (2)类型检查

    const常量与#define宏定义常量的区别:const常量具有类型,编译器可以进行安全检查;#define宏定义没有数据类型,只是简单的字符串替换,不能进行安全检查。

    (3)防止修改,起保护作用,增加程序健壮性

    1. void f(const int i){
    2.     i++; //error!
    3. }


    (4)可以节省空间,避免不必要的内存分配

    const定义常量从汇编的角度来看,只是给出了对应的内存地址,而不是像#define一样给出的是立即数,所以,const定义的常量在程序运行过程中只有一份拷贝,而#define定义的常量在内存中有若干个拷贝。
    这里写的非常清楚,我这里就不加累述了

    C语言|const的使用_const在c语言中的用法-CSDN博客

    C++ const的用法详解_c++ const用法-CSDN博客

    四、static详解

    【C语言】 Static关键字的用法和详解(太细了!!!)_static在c语言中的用法-CSDN博客

    详细说明: 

    • 变量会被放在程序的全局存储区中,这样可以在下一次调用的时候还可以保持原来的赋值。这一点是它与堆栈变量和堆变量的区别。 
    • 变量用static告知编译器,自己仅仅在变量的作用范围内可见。这一点是它与全局变量的区别。 
    • static修饰局部变量时,会改变局部变量的存储位置,从而使得局部变量的生命周期变长。
    • 当static用来修饰全局变量时,它就改变了全局变量的作用域,使其不能被别的程序extern,限制在了当前文件里,但是没有改变其存放位置,还是在全局静态储存区。

    使用注意: 
        1>若全局变量仅在单个C文件中访问,则可以将这个变量修改为静态全局变量,以降低模块间的耦合度; 
        2>若全局变量仅由单个函数访问,则可以将这个变量改为该函数的静态局部变量,以降低模块间的耦合度; 
        3>设计和使用访问动态全局变量、静态全局变量、静态局部变量的函数时,需要考虑重入问题(只要输入数据相同就应产生相同的输出)。

    五、extern详解

    extern 意为“外来的”···它的作用在于告诉编译器:有这个变量,它可能不存在当前的文件中,但它肯定要存在于工程中的某一个源文件中或者一个Dll的输出中。

    语法

    extern放在变量和函数声明之前,表示该变量或者函数在别的文件中已经定义,提示编译器在编译时要从别的文件中寻找。除此之外,extern还可以用来进行链接指定。

    作用

    1. 声明外部变量
      在声明全局变量时,不同的文件在编译器编译时是不透明的,比如在A.c中定义int i,同时在B.c中定义int i,编译器编译时是不会报错的,但是当链接linking时会报错重复定义。当需要使用同一全局变量时,如:在A.c中定义了int i,在B.c中需要调用i,只需要在B.c中声明extern int i,表示该变量在别的文件中已经定义,编译时便不会出错,在linking…的时候会自动去查找定义过的变量i。
    2. extern函数声明
      extern void fun()暗示该函数可能在别的文件中定义过,它和定义为void fun(),没什么区别,其用处在于复杂的项目用通过在函数前添加extern声明来取代用include" *.h"来声明函数。
    3. 单方面修改函数原型
      当声明extern void fun(int i,int j,int k)时,在之后的调用中如果按照是fun(x,y,z)的原型调用时是没有问题的,但是如果要对该函数进行修改比如输入参数,调用时为fun(x,y)此时编译器就会报错了,解决办法就是去掉extern,该头文件中声明void fun(int i,int j),并对该函数进行修改,之后在调用的文件中包含该函数所在的头文件" *.h"即可。

    六、auto详解

    这个这个关键字用于声明变量的生存期为自动,即将不在任何类、结构、枚举、联合和函数中定义的变量视为全局变量,而在函数中定义的变量视为局部变量。这个关键字不怎么多写,因为所有的变量默认就是auto的。

  • 相关阅读:
    一文读懂简单查询代价估算
    STC单片机16——将输入信号2倍频
    依葫芦画瓢理解一个小型Go框架
    机器学习之回归
    Xilinx FPGA 7系列 GTX/GTH Transceivers (3) Aurora 8b10b
    [洛谷] P1097 [NOIP2007 提高组] 统计数字
    智能网联赋能汽车品牌全球化 第五届全球汽车发展趋势论坛将召开
    【云计算 | Openstack】KVM虚机通过dhcp自动获取地址
    简单的咖啡文化静态HTML网页设计作品 DIV布局咖啡馆文化网页模板代码 DW咖啡网站制作成品
    QGradient(渐变填充)
  • 原文地址:https://blog.csdn.net/qq_51519091/article/details/133612368