1. 声明和定义

​  当定义一个变量的时候,就包含了对该变量声明的过程,同时在内存张申请了一块内存空间。如果在多个文件中使用相同的变量,为了避免重复定义,就必须将声明和定义分离开来。定义是创建与名字关联的实体。声明是让名字为程序所知,当一个文件想要使用其他文件定义的某个变量,则必须包含对那个文件的声明:

  1. 函数和变量的声明不会分配内存, 但是定义会分配相应的内存空间

  2. 函数和变量的声明可以有很多次, 但是定义最多只能有一次

  3. 函数的声明和定义方式默认都是 extern 的, 即函数默认是全局的

  4. 变量的声明和定义方式默认都是局部的, 在当前编译单元或者文件内可用

  了解声明和定义对static和extern的理解有辅助作用。比如extern就是在一处定义,其他文件都只需要声明即可,不可重复定义。

2. static& extern

2.1 static

  一般局部变量是存储在栈区的,局部变量的生命周期在其所在的语句块执行结束时便结束了。但如果用static修饰局部变量,那么这个变量就不会存储在栈区而是放在静态数据区,其生命周期会一直持续到整个程序结束,该变量只在初次运行时进行初始化,且只进行一次,但是它的作用域只能是在函数里面如下:

void print(){
static int z = 100;
z++;
cout << z <<endl;
}

int main(){
print();
print();
print();
return 0;
}

局部静态变量z只能在本文件的print函数里面访问,一旦超出作用域范围,就无法访问。

  如果是static修饰的全局变量,且实现的函数写在头文件(h)中,在其他文件也可以访问,如下:

//  a.h
#ifndef A_H
#define A_H
#include<iostream>
using namespace std;
static char str[] = "hello";
namespace sextern {
void print1();
void Fun1();
void Fun1(){
str[0] = 'l';
}
void print1(){
cout << "value " << str <<endl;
cout << "address " << &str <<endl;
}
}
#endif // A_H


//b.h
#ifndef B_H
#define B_H
namespace sextern{
void Fun2(){
str[0] = 'o';
}
void print2(){
cout << "value " << str <<endl;
cout << "address " << &str <<endl;
}
#endif // B_H

//main.cpp
#include "a.h"
#include "b.h"
using namespace sextern;
int main(int argc, char *argv[])
{
sextern::Fun1();
print1();
sextern::Fun2();
print2();
print1();
return 0;
}

//结果如下
/*
* value lello
* address 0x601058
* value oello
* address 0x601058
* value oello
* address 0x601058
* 按 <RETURN> 来关闭窗口...
*/

发现将static全局变量写在头文件中,所有文件的头文件的操作都会共享这个变量。

​   但如果是在源文件(cpp)中去操作这个静态全局变量,则这个静态全局变量只能在当前文件有效,但是在另外一个文件访问此静态变量,会是该变量初始的默认值,不会是其他文件中修改的值,虽然它们有相同的初始内容,但是存储的物理地址并不一样。如下:

//a.h
#ifndef A_H
#define A_H
#include<iostream>
using namespace std;
static char str[] = "hello";
namespace sextern {
void Fun1();
void print1();
}
#endif // A_H

//a.cpp
#include "a.h"
namespace sextern {
void Fun1(){
str[0] = 'l';
}
void print1(){
cout << "value " << str << endl;
cout << "address " << &str <<endl;
}
}

//c.h
#ifndef C_H
#define C_H
#include<iostream>
using namespace std;
namespace sextern {
void Fun3();
void print3();
}
#endif // C_H

//c.cpp
#include "c.h"
#include "a.h"
namespace sextern {
void Fun3(){
str[0] = 'o';
}
void print3(){
cout << "value " << str <<endl;
cout << "address " << &str <<endl;
}
}


#include "a.h"
#include "c.h"
using namespace sextern;
int main(int argc, char *argv[])
{
sextern::Fun1();
print1();
sextern::Fun3();
print3();
print1();
return 0;
}

//结果如下
/*
* value lello
* address 0x602064
* value oello
* address 0x60205e
* value lello
* address 0x602064
* 按 <RETURN> 来关闭窗口...
*/

在a.h的头文件中定义了一个静态的全局变量x,不同文件的函数fun1和fun3会为每个包含该头文件的cpp都创建一个全局变量,但他们都是独立的,只在该cpp文件共享该变量。所以一般定义static全局变量时,都把它放在原文件中而不是头文件,从而避免多个源文件共享,就不会给其他模块造成不必要的信息污染。如果想要在不同文件共享同一个全局变量,这个时候就要用到extern。

2.2 extern

  当在某个文件定义了一个全局变量,如果要在另一个文件去使用该变量,如果再次去定义,则会出现重复定义的问题,这个时候就需要使用到声明,对该变量的声明告诉编译器该变量在其他文件中已经定义,在此处要去引用它。上述的代码改成如下形式:

//b.h
#ifndef B_H
#define B_H
char str[] = "hello"; //定义一个全局变量
#endif // B_H

//a.h
#ifndef A_H
#define A_H
#include<iostream>
using namespace std;
extern char str[];
namespace sextern {
void Fun1();
void print1();
}
#endif // A_H

//a.cpp
#include "a.h"
namespace sextern {
void Fun1(){
str[0] = 'l';
}
void print1(){
cout << "value " << str << endl;
cout << "address " << &str <<endl;
}
}

//c.h
#ifndef C_H
#define C_H
#include<iostream>
using namespace std;
extern char str[];
namespace sextern {
void Fun3();
void print3();
}
#endif // C_H

//c.cpp
#include "c.h"
namespace sextern {
void Fun3(){
str[0] = 'o';
}
void print3(){
cout << "value " << str <<endl;
cout << "address " << &str <<endl;
}
}

//结果如下
/*
* value lello
* address 0x602058
* value oello
* address 0x602058
* value oello
* address 0x602058
* 按 <RETURN> 来关闭窗口...
*/

参考资料

详解C/C++中的static和extern

C/C++中extern关键字详解

extern和static区别的更多相关文章

  1. 全局变量,extern和static以及命名空间的区别

    全局变量,extern和static以及命名空间的区别        全局变量只是在声明它的文件中有效,假如在另一个文件中声明定义了一个相同名称的全局变量,则在后续使用这两个变量的时候会产生名字上的冲 ...

  2. 话说extern和static

    以前对extern.static的一些东西一直模棱两可.今天好好来梳理了一番.. static关键字 被static修饰的变量或函数称之为静态成员.函数. 存储位置:static修饰的变量存放在静态区 ...

  3. 链接(extern、static关键词\头文件\静态库\共享库)

    原文链接:http://www.orlion.ga/781/ 一. 多目标文件的链接 假设有两个文件:stack.c: /* stack.c */ char stack[512]; int top = ...

  4. IOS的变量前加extern和static字段

    IOS的变量前加extern和static字段 前一阵子,做项目的时候到网上找Demo,打开运行的时候发现其中变量前有关键字extern和static,所以我研究了一下子 对于extern来说可以理解 ...

  5. [C]控制外部变量访问权限的extern和static关键字

    一.extern 概述 编译器是由上至下编译源文件的,当遇到一些函数引用外部全局变量,而这个变量被定义在该函数声明主体的下方,又或者引用自其它的编译单元,这个情况就需要extern来向编译器表明此变量 ...

  6. C++中extern “C”含义及extern、static关键字浅析

    https://blog.csdn.net/bzhxuexi/article/details/31782445 1.引言 C++语言的创建初衷是“a better C”,但是这并不意味着C++中类似C ...

  7. 存储类型auto,static,extern,register的区别 <转>

    变量和函数的属性包括数据类型和数据的存储类别,存储类别指数据在内存中存储方式(静态和动态),包含auto,static,register,extern四种. 内存中.具体点来说内存分为三块:静态区,堆 ...

  8. iOS中的extern与static

    1.extern #import <Foundation/Foundation.h> extern NSString *DBDefaultName; @interface DataBase ...

  9. C语言关键字register、extern、static

    C语言中: 一.register变量 关键字regiter请求编译器尽可能的将变量存在CPU的寄存器中.有以下几点注意的地方. register变量必须是能被CPU寄存器所接受的类型,这通常意味着re ...

随机推荐

  1. __declspec的15种用法

    __cdecl和__stdcall都是函数调用规范(还有一个__fastcall),规定了参数出入栈的顺序和方法,如果只用VC编程的话可以不用关心,但是要在C++和Pascal等其他语言通信的时候就要 ...

  2. Fabric-Crashlytics-Android 注意点

    Fabric-Crashlytics-Android 注意点 非发布版本关闭Fabirc 官方文档中有这方面的介绍,有助于在开发过程中,提高编译速度和避免上报不必要的Crash 链接 一共两步 第一步 ...

  3. 了解 XML 数字签名

    http://www.cnblogs.com/flyxing/articles/91734.html http://www.cnblogs.com/wuhong/archive/2010/12/20/ ...

  4. DevExpress的xtraMessageBox汉化

    原文:DevExpress的xtraMessageBox汉化 项目使用的界面库是DevExpress 相当好用,不过里面弹出对话框XtraMessageBox的按钮都是英文的, 可能会对用户造成困扰, ...

  5. 算法之--回溯法-迷宫问题【python实现】

    题目描述 定义一个二维数组N*M(其中2<=N<=10;2<=M<=10),如5 × 5数组下所示: int maze[5][5] = { 0, 1, 0, 0, 0, 0,  ...

  6. windows和linux双系统,重新分区后修复grub

    我电脑里装的是 windows 7 profressional 和 fedora 12 ,本来给 C 盘分了 50G ,原本以为够了,结果50G 瞬间用完,于是乎开始重新分区. PQ 是不能用了,上网 ...

  7. C++函数不写bool返回值,居然编译运行全部通过,但判断结果就不对了

    bool MyStart::IsCoorectParam(QString strParam) { if (strParam=="-aa" || strParam=="-b ...

  8. Elevate Web Builder for Web Developers(类似于unigui的东西)

    推荐一款pascal 语言的web 开发工具 这几天仔细研究了一款使用Pascal 语言开发web 的工具 具体介绍可以参照这里. 先上几张他开发的页面照.

  9. 浅议Delphi中的Windows API调用(举的两个例子分别是String和API,都不错,挺具有代表性)

    浅议Delphi中的Windows API调用http://tech.163.com/school • 2005-08-15 10:57:41 • 来源: 天极网为了能在Windows下快速开发应用程 ...

  10. qtchooser - a wrapper used to select between Qt development binary(2种方法)

    ---------------------------------------------------------------------------------------------------- ...