C语言代码是以文件为单位来组织的,在一个源程序的所有源文件中,一个外部变量(注意不是局部变量)或者函数只能在一个源程序中定义一次,如果有重复定义的话编译器就会报错。
伴随着不同源文件变量和函数之间的相互引用以及相互独立的关系,产生了extern和static关键字。
下面,详细分析一下static关键字在编写程序时有的三大类用法:
1、static定义全局变量
一个进程在内存中的布局如图1所示:
其中.text段
保存进程所执行的程序二进制文件,.data段
保存进程所有的已初始化的全局变量,.bss段
保存进程未初始化的全局变量(其他段中还有很多乱七八糟的段,暂且不表)。在进程的整个生命周期中,.data和.bss段内的数据时跟整个进程同生共死的,也就是在进程结束之后这些数据才会寿终就寝。
当一个进程的全局变量被声明为static之后,它的中文名叫静态全局变量
。静态全局变量和其他的全局变量的存储地点并没有区别,都是在.data段(已初始化)或者.bss段(未初始化)内,但是它只在定义它的源文件内有效,其他源文件无法访问它。所以,普通全局变量穿上static外衣后,它就变成了新娘,已心有所属,只能被定义它的源文件(新郎)中的变量或函数访问。
以下是示例程序:
file1.h如下:
#include <stdio.h>
void printStr();
我们在file1.c中定义一个静态全局变量hello, 供file1.c中的函数printStr访问。
#include "file1.h"
static char* hello = "hello ZhengNian!";
void printStr()
{
printf("%s\n", hello);
}
main.c如下:
#include "file1.h"
int main()
{
printStr();
printf("%s\n", hello);
return 0;
}
main.c是我们的主程序所在文件,main.c中如果引用hello会编译出错,报错如下:
如果我们将main.c改为下面的形式:
#include "file1.h"
int main()
{
printStr();
return 0;
}
则会顺利编译连接。运行结果如下:
2、static定义局部变量
static局部变量中文名叫静态局部变量。它与普通的局部变量比起来有如下几个区别:
(1)位置:静态局部变量被编译器放在全局存储区.data(注意:不在.bss段内,原因见(3)),所以它虽然是局部的,但是在程序的整个生命周期中存在。
(2)访问权限:静态局部变量只能被其作用域内的变量或函数访问。也就是说虽然它会在程序的整个生命周期中存在,由于它是static的,它不能被其他的函数和源文件访问。
(3)值:静态局部变量如果没有被用户初始化,则会被编译器自动赋值为0,以后每次调用静态局部变量的时候都用上次调用后的值。这个比较好理解,每次函数调用静态局部变量的时候都修改它然后离开,下次读的时候从全局存储区读出的静态局部变量就是上次修改后的值。
以下是示例程序:
#include <stdio.h>
void test(void)
{
int normal_var = 0;
static int static_var = 0;
printf("normal_var:%d static_var:%d\n", normal_var, static_var);
normal_var++;
static_var++;
}
int main(void)
{
int i;
for ( i = 0; i < 3; i++)
{
test();
}
return 0;
}
运行结果如下:
可以看出,函数每次被调用,普通局部变量都是重新分配,而静态局部变量保持上次调用的值不变。
需要注意的是由于static局部变量的这种特性,使得含静态局部变量的函数变得不可重入,即每次调用可能会产生不同的结果。这在多线程编程时可能会成为一种隐患。需要多加注意。
3、static定义函数
当你的程序中有很多个源文件的时候,你肯定会让某个源文件只提供一些外界需要的接口,其他的函数可能是为了实现这些接口而编写,这些其他的函数你可能并不希望被外界(非本源文件)所看到,这时候就可以用static修饰这些“其他的函数”。
所以static函数的作用域是本源文件。static定义函数与static定义全局变量类似,不再举例说明,可参考“static定义全局变量”的程序定义全局变量的套路。
以上就是关于static的三种用法,欢迎转发!