static关键字
static 三大用法
- 静态全局变量
- 静态局部变量
- 静态函数
1. 静态全局变量
一个进程在内存中的布局如下图所示:
其中
.text 段
存储进程执行程序的二进制文件
.data 段
存储进程中已初始化的全局变量
.bss 段
存储进程中未初始化的全局变量
将一个全局变量用 static
修饰以后, 它的存储位置并没有什么不同, 还是在 .data
或者 .bss
中
但是这个变量现在只能在定义它的源文件内使用, 别的源文件无法访问, 即使用 extern
关键字声明了, 也不可以
举例如下:
test.h
#pragma once
#include <stdio.h>
void printStr();
test01.c
#include "test.h"
// 1. 静态全局变量
static const char* hello = "hello";
void printStr()
{
printf("%s\n", hello);
}
test02.c
#include "test.h"
extern char* hello;
int main()
{
printf("%s\n", hello);
printStr();
}
此时我们执行代码
明显在 test02.c 中找不到变量 hello, 因为 hello 在 test01.c 中被 static 修饰了, 它就只能在 test01.c 中被使用
2. 静态局部变量
我们知道, 普通的局部变量存储在栈上, 每次调用函数, 局部变量在栈上的位置也不一定相同; 局部变量还可以在堆上申请内存, 但是用完要记得释放内存
局部变量被 static 修饰以后, 叫做静态局部变量, 它和普通局部变量有以下区别
存储位置
静态局部变量存储在
.data
区, 所以, 虽然它是局部变量, 但是生命周期是整个程序 (注意: 因为静态局部变量如果没有初始化, 编译器会默认初始化它, 因此它不会存在.bss
区)访问权限
仍然只能在它的作用域以内访问, 虽然生命周期是全局的, 但是访问权限还是局部的
初始化和赋值
静态局部变量如果没有被用户初始化,则会被编译器自动赋值为0,以后每次调用静态局部变量的时候都用上次调用后的值
每次函数调用静态局部变量的时候都修改它然后离开,下次读的时候从全局存储区读出的静态局部变量就是上次修改后的值
举例如下:
test01.c
#include "test.h"
void test()
{
int count = 0;
// 2. 静态局部变量
static int s_count = 0;
printf("count = %d, s_count = %d\n", count, s_count);
count++;
s_count++;
}
test02.c
#include "test.h"
int main()
{
test();
test();
test();
test();
}
结果:
我们发现, 普通局部变量, 每次调用都是 0, 而静态局部变量, 每次调用都是上次调用后的值.
注意: 由于static局部变量的这种特性,使得含静态局部变量的函数变得不可重入(即每次调用可能会产生不同的结果)
这在多线程编程时可能会有线程安全问题, 需要多加注意 !!!
3. 静态函数
有时候, 我们编写一些小的函数是为了实现另一个大的函数, 我们只想把大的那个暴露出去用, 而小的就不想暴露给外界, 这时候我们可以用 static 修饰这些小函数
因为 static 修饰的函数只在本源文件中有效
例如:
test.h
#pragma once
#include <stdio.h>
// 静态函数
static void func01();
void func02();
test01.c
#include "test.h"
// 3. 静态函数
static void func01()
{
printf("static func01");
}
void func02()
{
func01();
printf("func02");
}
test02.c
#include "test.h"
int main()
{
func01();
func02();
}
结果:
我们发现, 即使 .h
头文件中声明了函数 func01()
, 但编译时仍然会说找不到定义
我的 Makefile
也是没问题的
.PHONY:clean
main:test01.c test02.c
gcc $^ -o $@
clean:
rm -rf main
在这里, static 函数就相当于 C++ 中的 private 成员函数
static 函数可以很好地解决不同源文件中函数同名的问题,因为一个源文件中的 static 函数对于其他源文件是不可见的