C/C++中的静态变量,相信大多数人都用过,但你很可能用错了,包括你现在所在的项目中都可能埋着这个坑,不信我们往下看!
我们先来看一段大家常写的代码,很简单,这段代码没啥坑:
- #include
-
- int GetData()
- {
- static int a = 0;
- return a++;
- }
-
- int main()
- {
- for (int i = 0; i < 100; ++i)
- {
- printf("%d\n", GetData());
- }
- }
大家都清楚,静态变量只初始化一次,所以GetData调用了100次,打印的结果也是0-99,想必大家都很清楚 ,那请问GetData中初始化变量a的代码只会执行一次?是在哪个阶段初始静态局部变量a的?
想必大家都能回答上来,静态局部变量a的生命周期从程序运行开始就已经存在并初始化了的,并非是在GetData函数中初始化的,但又不完全对,我们看下一段代码:
- #include
-
- int GetA()
- {
- return 0;
- }
-
- int GetData()
- {
- static int a = GetA();
- return a++;
- }
-
- int main()
- {
- for (int i = 0; i < 100; ++i)
- {
- printf("%d\n", GetData());
- }
- }
看了这段代码,不知道大家有没有懵逼?问题来了,请问GetA函数会被调用几次?静态局部变量a是在什么时候初始化的?给大家5秒钟思考!
OK!静态局部变量无论如何都只会初始化一次,这是没有毛病的,但此时静态局部变量a是在第一次调用GetData函数的时候才被初始化的,与前一个例子用常量初始化静态变量并不相同,当然生命周期还是从程序运行开始到程序结束为止。
那编译器是怎么初始化静态变量a的呢?编译器会改造GetData方法如下:
- int GetData()
- {
- static bool init = false;
- if (!init)
- {
- a = GetA();//a已经被定义在全局了
- init = true;
- }
- return a++;
- }
这样编译器就可以保证静态变量a在GetData函数内只被初始化一次,但请问a的初始化是否线程安全?
当然,不同编译器的实现并不相同,有的编译器会在初始化全局变量a的时候用上临界区等,以保证初始化的线程安全,有的却并没有,当然为了自己的代码兼容性更强,建议不要这样写,随便换个方法都能替代。或者只使用常量去初始化静态变量,这能保证线程安全!
总结,编译器在我们不知道的地方默默付出,大家要知道感恩!