引言
static关键字在c/c++中的使用是十分广泛的。该关键字的作用很多,其中一个最常用的作用就是对函数或者变量进行隐藏:没有添加static的变量或者函数是全局可见的;而添加了static关键字的全局变量则被隐藏,利用这一特性可以在不同的文件中定义同名函数和同名变量,而不必担心命名冲突。
现在,如果想在.h文件中定义static变量,将它强行暴露出来,会发生什么情况呢?为了解决这一疑惑,笔者在windows下的vs2010环境中进行了试验。
Context
试验一:
笔者现在创建一个工程目录,目录结构如下:
~/workspace/Test
|-src
| |-A.h
| |-B.h
| |-main.cpp
| |-B.cpp
|-doc
| |-Test.txt
|-COPYRIGHT
|-README
头文件A.h,主要作用是在头文件A中定义了static变量a,将变量a暴露出来。
#ifndef _A_H_
#define _A_H_
static int a=0;
#endif
头文件B.h,声明了函数funB(),同时引入了头文件A.h。
#ifndef _B_H_
#define _B_H_
#include "A.h"
void funB();
#endif
B.cpp文件,定义了函数funB()。
#include "B.h"
#include<iostream>
using namespace std;
void funB()
{
cout<<"funB(): &a = "<<&a<<" , a = "<<a<<endl;
}
main.cpp文件。
#include <iostream>
#include "A.h"
#include "B.h"
using namespace std;
int main()
{
cout<<"main1(): &a = "<<&a<<" , a = "<<a<<endl;
a++;
cout<<"main2(): &a = "<<&a<<" , a = "<<a<<endl;
funB();
system("pause");
return 0;
}
因为a定义在.h文件中,如果a是一个全局变量,对于main.cpp和B.cpp都是可见的,那么在main函数中,a的值应该先为0,在main的末尾,应该为1,且a的地址都应该是一样的,但是,vs2010显示的结果如下:
结果表明,mian.cpp读取的a和B.cpp读取的变量a是两个不同的变量,拥有不同的地址空间,a在main.cpp和B.cpp中做到了互相独立。也就是说定义在头文件里的static变量,被其他模块每包含一次就申请一次内存!
试验二:
保持其他文件不变,只改变A.h中的static int a =0;
。将这句话改为 int a = 0;
,此时,工程无法通过编译,会报fatal error LNK1169: one or more multiply defined symbols found
错误,这个很好理解,因为没有static修饰后的变量a是一个全局变量,在main.cpp中和B.cpp中在全局空间中同时定义了两个名字相同的变量,会导致重定义的错误。同时结合试验一也再一次论证了,全局变量#include多次会出错,而static变量被#include多次会生成多个局部变量。
试验三:
笔者现在创建一个新的工程目录,目录结构如下:
~/workspace/Test
|-src
| |-B.h
| |-main.cpp
| |-B.cpp
|-doc
| |-Test.txt
|-COPYRIGHT
|-README
头文件B.h。
#ifndef _B_H_
#define _B_H_
void funB();
#endif
B.cpp文件,定义了函数funB()。
#include "B.h"
#include<iostream>
using namespace std;
static int a = 0;
void funB()
{
cout<<"funB(): &a = "<<&a<<" , a = "<<a<<endl;
}
main.cpp文件。
#include <iostream>
#include "A.h"
#include "B.h"
using namespace std;
extern int a;
int main()
{
cout<<"main1(): &a = "<<&a<<" , a = "<<a<<endl;
a++;
cout<<"main2(): &a = "<<&a<<" , a = "<<a<<endl;
funB();
system("pause");
return 0;
}
此时也会编译报错,报fatal error LNK1120: 1 unresolved externals
,因为static关键字修饰了变量a,使得变量a是B.cpp独占的,对main.cpp隐藏,即使用extern关键字修饰,main.cpp也无法解析。
试验四:
试验四在试验三的基础上,将B.cpp中的static int a = 0;
修改为int a = 0;
。缺少了static关键字修饰,利用extern自然可以将B.cpp中的a暴露给 main.cpp。
试验结果如下:
总结
上述的四次试验再一次证明了:变量不要在头文件中定义,要在.cpp文件中定义!全局变量#include多次会出错,而static变量被#include多次会生成多个局部变量。