static关键字的再思考

引言

       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
using namespace std;

void funB()
{
    cout<<"funB(): &a = "<<&a<<" , a = "<

       main.cpp文件。

#include 
#include "A.h"
#include "B.h"
using namespace std;

int main()
{
    
    cout<<"main1(): &a = "<<&a<<" , a = "<

       因为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
using namespace std;
static int a = 0;

void funB()
{
    cout<<"funB(): &a = "<<&a<<" , a = "<

       main.cpp文件。

#include 
#include "A.h"
#include "B.h"
using namespace std;
extern int a;

int main()
{
    
    cout<<"main1(): &a = "<<&a<<" , a = "<

       此时也会编译报错,报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多次会生成多个局部变量。

你可能感兴趣的:(static关键字的再思考)