一 static 关键字简介
二 static 的用途大全
先总结一下 static 的用法,然后再对每一条进行说明:
- 定义全局静态变量
- 定义局部静态变量
- 定义静态函数
- 头文件中使用
2.1. 定义全局静态变量
首先是全局静态变量,看这名字就知道,这个变量有两个属性(姑且就称之为属性吧),第一:这个变量是全局的,也就是说这个变量可以在源文件的任何一个函数中使用,并且始终存在。第二:这个函数是静态的,本来嘛,全局变量已经是能够一直存在,你加一个静态属性什么意思?静态,就是说你只能在本文件调用,其他文件调用是不行的,即使你用 extern 声明也不行,如果真这么做,这就是下场:
2.2. 定义局部静态变量
普通局部变量是再熟悉不过的变量了,在任何一个函数内部定义的变量(不加static修饰符)都属于这个范畴。编译器一般不对普通局部变量进行初始化,也就是说它的值在初始时是不确定的,除非对其显式赋值。
普通局部变量存储于进程栈空间,使用完毕会立即释放。
静态局部变量使用static修饰符定义,即使在声明时未赋初值,编译器也会把它初始化为0。且静态局部变量存储于进程的全局数据区,即使函数返回,它的值也会保持不变。
变量在全局数据区分配内存空间;编译器自动对其初始化
其作用域为局部作用域,当定义它的函数结束时,其作用域随之结束
2.3. 定义静态函数
静态函数:函数体是始终存在的,但是这里加了一个 static 什么意思,肯定不是让它始终存在,而是限制它的作用域。我们知道一个函数是可以被其他文件的函数调用的,但是现在加了这静态属性就不行了,这个函数只能被这个文件的函数调用,其他文件的函数是无法调用的,也正因为如此,所以其他文件也可以使用相同的函数名而不怕重复定义了,同理,全局静态变量和局部静态变量也是如此。
2.4. 头文件中使用
第一次看到 static 在头文件使用的时候是和 inline 一起使用的,所以在头文件的声明为一个内联函数。本来一个内联函数放在头文件中申明为 inline 就可以了,为什么还要加上 static 呢?
这是为了在不同文件中使用 include 包含头文件时能够产生不同的实体,这样就不会出现重复定义的情况了。
同理,如果你在头文件中用 static 申明一个变量,那么每次使用 include 包含这个头文件的时候都会产生一个变量,虽然它们的名字相同,但是它们内存位置却是不同的,比如张三这个名字,虽然都叫张三,但可能他们不是同一个人,所做的一些行为也就不一样了。
可以看到,我在 delay.h 中定义了一个 delay_time 的变量,在 main.c 和 usart1.c 两个文件中使用 include 包含这个 delay.h 文件,通过编译的 .map 文件可以看到,每一个文件下都有一个 delay_time,虽然名字一样,但是地址却不一样,一个是 0x20000000,另一是 0x20000010,所以它们是不同的变量。
三 static关键字与其他搭配使用
3.1. static inline
3.3.1 static inline 函数 为什么要放在头文件中定义?
如果不放在头文件中定义,其他文件必须包含该文件才能实现函数替换,如果在C文件中定义static inline函数,这样是不合适的。 头文件是多文件编译中,文件引用的桥梁,其他文件都会引用头文件
3.3.1 为什么需要加上 static关键字?
在讲这个之前,其实我们需要知道一点。就是static inline关键字和inline关键字无法决定被关键字所修饰的函数是否最后真正会被内联。我们其实只有建议权,只有armcc编译器才可以决定函数最后是否真正会被内联。
我们把Inline_Add函数放在了一个头文件。试想,如果这个Inline_Add在没有被编译成内联函数的情况下,被include到了多个源文件中,势必会产生函数重复定义的问题。 因此,我们要再加一个关键字static,才能避免这个问题。
参考文章:
C语言系列文章之static - 知乎 https://zhuanlan.zhihu.com/p/59496411
详解static inline关键字 - 知乎 https://zhuanlan.zhihu.com/p/132726037