关于static变量存在周期和函数不可重入的问题

 

一、概念

  1. static:顾名思义静态变量就是安静的保存在一个地方,等到需要用到的地方再去读取,但是其存在的周期是一直到整个程序的结束(也就是说程序不死它一直存在),无论你是静态局部变量还是静态全局变量,它都会在内存中单独开辟一个空间存放,直到程序结束,这就关乎到函数的重入问题,下面我们再讲。与静态变量相对的就是动态变量,所谓动态变量,就是在定义以后在堆栈中存储的变量,这个变量在程序执行过程中,使用它时才分配存储单元,使用完毕立即释放。所以动态变量的存在周期是它所作用的函数内,当函数消亡时,该变量也被release。
  2. 可重入函数:所谓可重入函数,就是函数如果突然被打断,等到重新完成上下文切换,继续执行的时候,不会影响当前堆栈中该函数的变量,从而不会影响到函数的输出结果。说到这不得不提及一下函数在调用时候的堆栈方式,这里以单片机举例。了解arm的人都知道,当我们给单片机写程序的时候。如果发生函数的调用。程序就会将当前正在执行函数的变量和状态值统一从寄存器r0~r15(笼统的说法,具体看内核工作在哪种模式,举例按照工作在user模式)中读出并压入栈(stack、ram)中,将cpsr的值备份到spsr中。等到重新回到该函数的时候再重新出栈,将之前复制的值写入到寄存器中,然后再继续程序的运行。
  3. static变量与不可重入函数:如果在函数中使用了静态变量或者全局变量,那么这个函数就是不可重入函数,在一般时候我们应当避免写不可重入的函数,当然如果你只是不含中断的裸机程序,那就看你个人的喜好了emmm~。当你在函数中或者函数外定义一个静态变量的时候,在初始化的时候是存放在全局区(静态区)(static)—全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后由系统释放。当然并不是说static变量全无好处,若全局变量仅在单个C文件中访问,则可以将这个变量修改为静态全局变量,以降低模块间的耦合度;若全局变量仅由单个函数访问,则可以将这个变量改为该函数的静态局部变量,以降低模块间的耦合度;

     

二、举例 

到这里可能还是会有些搞不清楚,下面我们举个例子来观察一下:(以下环境为codeblock)

我们把静态变量放到一个简单的函数中,然后再去调用,然后打印出该值,并观察在函数调用结束后,该静态变量的值:

#include <stdio.h>
#include <stdlib.h>
void abc()
{
    static int a = 0 ;
    a++;
    printf("a=%d\n",a);
}


int main()
{
    abc();
    abc();

}

运行结果:

可以看到当发生第一次函数调用的时候,a的值被加了1,函数调用结束以后a的值并没有释放,等到第二次调用的时候,a的值又被加1,打印出来的值就为2。

为了对比我们再试一次在堆栈上定义一个变量,观察现象:

#include <stdio.h>
#include <stdlib.h>


void abc()
{
    static int a = 0 ;
    a++;
    printf("a=%d\n",a);
}

void bcd()
{
    int b = 0 ;
    b++;
    printf("b=%d\n",b);
}
int main()
{
    abc();
    abc();
    bcd();
    bcd();
}

运行结果:

明显,当我们第一次调用这个局部变量b的时候它的作用域仅仅在这个函数中,等到函数调用结束,b被释放,第二次的时候会再次在栈上申请空间,那么b的值会被再次初始化,于是两次打印出来的值的结果都是相同的。

三、应用

在实际的使用过程中我们经常需要在函数或者中断中使用全局变量,为了使函数不会产生不可预估的输出,我们经常用到一些特殊的方法来防止被调用全局区变量时,被其他程序打断。比如一些嵌入式操作系统,当存在多任务或者多线程时,为了使函数在操作全局变量的时候不被其他任务或者线程打断,此时会用到临界区,信号量,互斥锁等等,这样就可以确保函数调用共享资源时的安全性。

具体可以参见以下连接:临界区,互斥量,信号量,事件的区别

此外,写单片机裸机程序的小伙伴,建议尽量不要在中断函数中调用全局变量,一般用一个flag取而代之。中断函数结束后,通过判断标志再执行后续的操作。一方面可以保护数据的安全,另一方面还能加快中断响应速度。

 

四、总结

关于静态变量和不可重入的函数大致如此,如有不正确的地方,欢迎指正。

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值