C语言基础:static的使用

本文结合工作经验,研究C语言中static关键字的用法。

1 static关键字概念

static关键字在C语言中非常常用,博主工作中常见三种用法:修饰全局变量、修饰局部变量以及修饰函数。通过static关键字的修饰,可以使被修饰的变量或函数只在作用域中有效,类似一种私有化的机制。

2 用法与使用场景

2.1 修饰全局变量

2.1.1 代码示例

在函数外定义的变量称为全局变量。全局二字表示,在其他的c文件中也可以调用这个变量。

例如如下代码demo1.c,main.c:

//demo1.c

int demo_a;

void demo1(void)
{
	demo_a = 10;
}
//main.c

#include <stdio.h>

extern int demo_a;
extern void demo1(void);

int main()
{
    demo1();
    printf("demo_a = %d\n", demo_a);
}

首先,在demo1.c中定义了一个全局变量demo_a,以及一个函数demo1(void)用于将10赋值给全局变量。

然后,在main函数中通过extern关键字,外部声明全局变量demo_a和函数demo1(void)。在main函数内部先通过调用demo1()将demo_a赋值为10,再编译软件打印出来。

打印在控制台上的结果如下:

在这里插入图片描述
这个demo对熟悉C语言的人来说是小菜一碟。之所以能在其他c文件中调用到demo_a的值,是因为全局变量的作用域为整个工程的c文件中。

接着在这个基础上,如果加上关键字static修饰全局变量demo_a,如下图:

//demo1.c

static int demo_a;//加上关键字static修饰全局变量demo_a

void demo1(void)
{
	demo_a = 10;
}

再编译一下就会报错:
在这里插入图片描述
这里报错的意思是,在软件链接的过程中,搜索工程中所有的c文件都无法找到demo_a这个变量。因为static关键字将demo_a这个变量的作用域限定在demo1.c这个文件中才可以使用了,外部其他文件即使extern声明了也无法引用。

2.1.2 使用场景

博主工作经验中,这种用static修饰全局变量,是为了将该全局变量限定在自身的c文件中使用,防止其他c文件随意地篡改掉。例如上一节中的做法,外部文件是完全无法访问到demo_a的值的。

如果想要获取静态全局变量的数值该怎么办呢。可以通过调用函数返回值获取,把代码改成下图所示。

//main.c

#include <stdio.h>

extern int demo1(void);

int main()
{
    int demo_a = demo1();    
    printf("demo_a = %d\n", demo_a);
}

//demo1.c

static int demo_a;

int demo1(void)
{
	demo_a = 10;
	return demo_a;
}

将demo_a的数值通过demo1()函数返回给main函数,这样外部就可以获得该静态全局变量的值。注意一点,demo1.c和main.c文件中都出现了demo_a变量,但不是一回事,一个是静态全局变量,另一个是函数中的局部变量。也就是说,在main函数中将局部变量demo_a的值改成其他的值(例如20),是不会影响到demo1.c文件中的静态全局变量demo_a的。这样,也就使得外部文件只能读不能写,达到了既能给外界传递信息,又能防篡改的效果。

2.2 修饰函数

2.2.1 代码示例

将上一节的代码稍微改一下,如下:
例如如下代码demo1.c,main.c:

//demo1.c

int demo_a;

static void demo1(void)
{
	demo_a = 10;
}
//main.c

#include <stdio.h>

extern int demo_a;
extern void demo1(void);

int main()
{
    demo1();
    printf("demo_a = %d\n", demo_a);
}

将demo1.c中的demo1(void)函数定义之前加上static关键字,就成为了静态函数。这时候在main函数中通过extern外部声明demo1(void)函数,就无法调用了,运行结果如下:
在这里插入图片描述
报错就和上一节类似,找不到demo1(void)这个函数的定义。static关键字也将这个函数的作用域限定在本文件中。

把代码稍微改一改,改成如下嵌套调用的形式:

//main.c

#include <stdio.h>

extern int demo_a;
extern void demo(void);

int main()
{
    demo();
    printf("demo_a = %d\n", demo_a);
}

//demo1.c

int demo_a;

static void demo1(void)
{
	demo_a = 10;
}

void demo(void)
{
	demo1();//demo()函数中调用demo1()静态函数
}

这样在运行一下,就能正常地打印出来了。

这说明static修饰的函数只能在该文件内部被别的函数调用,不能在别的文件通过extern外部声明调用到。

2.2.2 使用场景

博主在工作中遇到static修饰函数地使用场景是,一个文件地函数中划分了若干个功能,提取为几个子函数,将这几个子函数用static修饰成静态函数。这样做防止外部函数调用子函数,只限制在该文件内调用。

例如如下代码:

//demo1.c

static void demo1(void)
{
	demo_a = 10;
}

static void demo1(void)
{
	printf("demo_a = %d\n", demo_a);
}

void demo(void)
{
	demo1();
	demo2();
}

demo(void)函数调用了自身c文件的两个其他的静态函数,这两个静态函数分别实现两个功能:赋值与打印。然后别的外部函数可以调用非静态的demo(void)函数,从而执行下面的两个子函数。

2.3 修饰局部变量

局部变量定义在某个函数内部,作用域仅限于该函数,函数运行完毕后就被释放掉了。如果在局部变量之前加上static修饰,就会不一样。

2.3.1 代码示例

首先举个简单的局部变量的例子:

//main.c

#include <stdio.h>

void demo(void)
{
    int a = 0;
    a++;
    printf("%d ", a);
}

int main()
{
    for (int i = 0; i < 5; i++)
    {
        demo();
    }
}

在demo()函数中定义一个局部变量a,初始化为0,接着自加1并打印出来。在main函数中通过for循环调用5次demo()函数,查看5次的打印结果如下:
在这里插入图片描述
这里打印出来了5个1,是因为每次进入demo()函数,int a都会新开辟一个栈空间存储这个临时变量,并初始化为0。接着自加1并打印,所以每次都输出1。

接着,稍微改一下代码,在int a局部变量定义之前加上static修饰,代码改为如下:

//main.c

#include <stdio.h>

void demo(void)
{
    static int a = 0;//加上static修饰
    a++;
    printf("%d ", a);
}

int main()
{
    for (int i = 0; i < 5; i++)
    {
        demo();
    }
}

再次运行程序,打印如下:
在这里插入图片描述
打印的结果变为了12345,也就是说,每次调用demo()函数后,a的值保留到了下一次调用,再自加1打印出来。

这里的原因是static关键字将局部变量a变成了静态局部变量。静态局部变量的特点是不会在函数调用后释放掉,而是在编译好了以后直接分配一个固定的地址并直接初始化为0(这一点类似于全局变量)。当每次demo()函数运行时,由于a已经预先定义好了,就不会执行static int a = 0;这一句语句。

2.4.2 使用场景

static局部变量能达到一个保留变量数值不被释放掉的效果,这一点在嵌入式C语言开发中非常有用。在周期调度某个函数时,static修饰的局部变量就可以保留上一周期的值。

举个一阶滤波算法的例子,一阶滤波公式如下:

Y(n) = α*X(n) + (1−α)*Y(n−1)

一阶滤波的输出值需要依赖上一次的输入值,所以就可以用一个静态局部变量存储本周期的输出值,到了下次调用函数的时候就成为了上次的输出值。参考如下代码。

#define Alpha 0.8

void first_order_filter(float input,float* output)
{
    static float output_previous = 0;
    *output = (1 - Alpha) * output_previous + input * Alpha;
    output_previous = *output;
}

3 总结

在工作中常见以上三种static关键字的使用方法。

>>返回个人博客总目录

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值