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<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多次会生成多个局部变量。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,907评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,987评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,298评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,586评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,633评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,488评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,275评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,176评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,619评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,819评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,932评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,655评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,265评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,871评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,994评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,095评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,884评论 2 354

推荐阅读更多精彩内容

  • mean to add the formatted="false" attribute?.[ 46% 47325/...
    ProZoom阅读 2,696评论 0 3
  • 在C语言中,五种基本数据类型存储空间长度的排列顺序是: A)char B)char=int<=float C)ch...
    夏天再来阅读 3,342评论 0 2
  • 1 原理 1.1 首先,关于声明和定义的区别。 这种写法(函数原型后加;号表示结束的写法)只能叫函数声明而不能叫函...
    Pitfalls阅读 6,492评论 2 12
  • 很喜欢冯唐的文字:简洁干练直白,不装不作不无病呻吟,有深度高度。 峰子自诩为:唐粉 严重认同他认为码字人应:感受在...
    冰语夏虫阅读 542评论 0 3
  • Java 程序是如何跑起来的呢,如何从一个 .java 源文件到控制台的输出结果?要回答类似的问题就需要学习虚拟机...
    云大数据社区阅读 583评论 0 8