当前位置:首页 > 单片机 > C语言与CPP编程
[导读][导读] static的用法对于很多刚刚开始接触开发的朋友来说,可能没理解其真正的用途, 虽说这个是老生常谈的话题 ,但这也是高频面试要点,所以本文来聊聊。 最近有点小忙,更文慢了些,抱歉。 先谈存储类型 存储类型表示变量的可见性和位置。它告诉可以从代码

[导读] static的用法对于很多刚刚开始接触开发的朋友来说,可能没理解其真正的用途, 虽说这个是老生常谈的话题 ,但这也是高频面试要点,所以本文来聊聊。

最近有点小忙,更文慢了些,抱歉。

先谈存储类型

存储类型表示变量的可见性和位置。它告诉可以从代码的哪一部分访问变量。存储类用于描述以下内容:

  • 变量的作用域(scope),作用域指存取变量的代码范围。
  • 变量从哪里分配存储内存。
  • 变量的初始化值。
  • 变量的生命周期(lifetime),生命周期指存取变量的时间范围,从程序运行时角度去考察变量的。

那么有哪些存储类型呢?下面几个词是C语言描述存储类型的关键字:

  • auto : 自动型,为变量的默认存储方式,作用域从定义点到该局部程序块尾部,分配存储在栈内,生命周期程序运行至定义点出生,到程序运行退出该块时消亡。
  • extern:外部型,作用域为整个程序,其分配存储在数据段,生命周期为整个程序运行生命周期。
  • static:静态型,其分配存储在数据段,故其生命周期为整个程序运行生命周期,其作用域分两种情况:
    • 定义在文件中,则作用域为定义点至该文件尾部。
    • 定义在函数中,则作用域为定义点至该函数尾部。
  • register:寄存器型,寄存器存储类用于定义应存储在寄存器而不是RAM中的局部变量。 这意味着该变量的最大位长度等于寄存器的位长度(通常是一个字),并且不能对其使用'&'运算符(因为它没有存储在内存中)。仅应用于需要快速访问的变量(例如计数器)。还应注意定义“register”并不意味着变量将一定会存储在寄存器中。它可能根据不同硬件和实现限制存储在寄存器中。

由static来谈C封装

static用在文件中修饰变量,如下代码:

/*这是某模块文件,比如叫senor.c*/
#include "sensor.h"
static float sensor_value;
static float filter(float in)
{
    float out;
    
    /*这里实现滤波计算*/
    ......
        
    return out;
}
void update_sensor_exe(void)
{
     float temp   = adc_read();
     sensor_value = fileter(temp);
}

float get_sensor_value(void)
{
    return sensor_value;
}

这里定义其头文件,比如sensor.h

#ifdef  __SENSOR_H__
#define __SENSOR_H__

void update_sensor_exe(void);

#endif

用一个UML图来描述一下这个模块:

这样使用,是不是有点模块封装的意思呢,来总结一下:

  • 利用static定义属于模块的变量,可以将属于模块属性隐藏在模块内部,对外部不见,是不是有点类似对象语言中的private变量的赶脚呢?
  • static修饰函数成局部函数是不是也相当于面向对象语言中一个类的私有方法呢?如此,外部程序是无法调用filter函数的。
  • update_sensor_exe/get_sensor_value 为模块对外接口,这样一来使用者就可以不关心模块内部究竟是怎么做的,可以看成是个黑盒子,只需要知道update_sensor_exe更新了传感器采集,而调用get_sensor_value则可以返回获取到当前的测量数据。
  • static修饰变量可为广义对象,比如struct。这样可以将相关属性更为紧凑的封装,事实上这种用法是非常好的用法,也被广为使用。
  • C语言在多人协同开发时,利用static的这种用法时,系统设计人员定义模块或子系统接口,可以很好的解决同名变量/函数冲突,有利于协同并行开发。可以隐藏各自的实现细节,各自造各自的轮子,造整车的管造整车,从而较易实现系统集成。

对上述代码稍作总结,对一个使用该模块的程序员而言来看模块,就是下面这样一个视图:

static在函数内

#include 
int fun1() 

   int count = 0
   count++; 
   return count; 


int fun2() 

   static int count = 0
   count++; 
   return count; 


int main() 

   printf("fun1=%d\n", fun1()); 
   printf("fun1=%d\n", fun1());
    
   printf("fun2=%d\n", fun2()); 
   printf("fun2=%d\n", fun2());   
   return 0
}

由于一个自动型变量,一个是静态变量,存储位置不一样,生命周期也不一样,所以运行结果也不一样。

fun1=1
fun1=1
fun2=1
fun2=2

对于把函数内部变量定义为static型,个人建议是如某特性只与函数内需求或特性相关,则可以这样使用,如果不是则不建议将过多变量定义成函数内部静态变量。当然事无绝对,这个使用起来还是很灵活的。举个栗子:

  • 比如一个函数内部某些操作,在整个程序运行生命周期,只允许运行一次,这种特性属于私有特性,个人会采用下面这种策略。
void fun()
{
     static bool called = false;
     if(!called)
     {
        called = true;
        /*应用代码A*/
        .....
     }
     
     .....
}

这样当该函数在第一次运行时,将会调用应用代码A块,然后将标志设置为true,由于该变量生命周期为整个程序的生命周期,则该函数下次进入时,将不会调用应用代码A块。当然如果把这个标志用模块静态变量或者全局变量标记从功能上是一样的,这样放入内部的好处是这种需求的scope就是该函数内部,所以作用域与待实现的需求比较好的匹配。

总结一下

由于C语言不是对象语言,如能很好利用static关键字的语言特性,也可以实现些封装属性、开放接口的对象思想。当然C语言的对象编程策略绝不仅限于这一点。如能善用一些语言特点将会使代码变得更加紧凑、优雅。本文做了些简单示例总结,当然对于软件大牛而言,则显得颇为粗浅了。

本文辛苦原创总结,如果觉得有价值也请帮忙点赞/在看/转发支持,不胜感激!

END

免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: 驱动电源

在工业自动化蓬勃发展的当下,工业电机作为核心动力设备,其驱动电源的性能直接关系到整个系统的稳定性和可靠性。其中,反电动势抑制与过流保护是驱动电源设计中至关重要的两个环节,集成化方案的设计成为提升电机驱动性能的关键。

关键字: 工业电机 驱动电源

LED 驱动电源作为 LED 照明系统的 “心脏”,其稳定性直接决定了整个照明设备的使用寿命。然而,在实际应用中,LED 驱动电源易损坏的问题却十分常见,不仅增加了维护成本,还影响了用户体验。要解决这一问题,需从设计、生...

关键字: 驱动电源 照明系统 散热

根据LED驱动电源的公式,电感内电流波动大小和电感值成反比,输出纹波和输出电容值成反比。所以加大电感值和输出电容值可以减小纹波。

关键字: LED 设计 驱动电源

电动汽车(EV)作为新能源汽车的重要代表,正逐渐成为全球汽车产业的重要发展方向。电动汽车的核心技术之一是电机驱动控制系统,而绝缘栅双极型晶体管(IGBT)作为电机驱动系统中的关键元件,其性能直接影响到电动汽车的动力性能和...

关键字: 电动汽车 新能源 驱动电源

在现代城市建设中,街道及停车场照明作为基础设施的重要组成部分,其质量和效率直接关系到城市的公共安全、居民生活质量和能源利用效率。随着科技的进步,高亮度白光发光二极管(LED)因其独特的优势逐渐取代传统光源,成为大功率区域...

关键字: 发光二极管 驱动电源 LED

LED通用照明设计工程师会遇到许多挑战,如功率密度、功率因数校正(PFC)、空间受限和可靠性等。

关键字: LED 驱动电源 功率因数校正

在LED照明技术日益普及的今天,LED驱动电源的电磁干扰(EMI)问题成为了一个不可忽视的挑战。电磁干扰不仅会影响LED灯具的正常工作,还可能对周围电子设备造成不利影响,甚至引发系统故障。因此,采取有效的硬件措施来解决L...

关键字: LED照明技术 电磁干扰 驱动电源

开关电源具有效率高的特性,而且开关电源的变压器体积比串联稳压型电源的要小得多,电源电路比较整洁,整机重量也有所下降,所以,现在的LED驱动电源

关键字: LED 驱动电源 开关电源

LED驱动电源是把电源供应转换为特定的电压电流以驱动LED发光的电压转换器,通常情况下:LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: LED 隧道灯 驱动电源
关闭