extern和static区别
1. 声明和定义
当定义一个变量的时候,就包含了对该变量声明的过程,同时在内存张申请了一块内存空间。如果在多个文件中使用相同的变量,为了避免重复定义,就必须将声明和定义分离开来。定义是创建与名字关联的实体。声明是让名字为程序所知,当一个文件想要使用其他文件定义的某个变量,则必须包含对那个文件的声明:
函数和变量的声明不会分配内存, 但是定义会分配相应的内存空间
函数和变量的声明可以有很多次, 但是定义最多只能有一次
函数的声明和定义方式默认都是 extern 的, 即函数默认是全局的
变量的声明和定义方式默认都是局部的, 在当前编译单元或者文件内可用
了解声明和定义对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> 来关闭窗口...
*/
参考资料
最新文章
- VM12.1.1 下载 序列号
- Oracle Dataguard的原理与基本配置
- 如何预览github中的html页面
- DEDECMS如何修改数据库密码以及忘记了后台密码怎么办
- CF 136B Ternary Logic
- mybatis update语句参数正常, 数据没有更新
- 3. QT窗体间值的传递(续)
- 【Cocos得知】技术要点通常的积累
- ionic结合HTML5实现打电话功能
- BotVS开发基础—2.5 绘制图表
- Easyui 实现点击不同树节点打开不同tab页展示不同datagrid表数据设计
- Redis配置主从复制
- 2019.1.17 homework
- JAVA自学笔记22
- HBase的写事务,MVCC及新的写线程模型
- Java 利用 poi 生成 Excel文件的通用例子
- Java编程的逻辑 (63) - 实用序列化: JSON/XML/MessagePack
- 10.Set 和 Map 数据结构
- etcd 分布式数据库概念初探
- VBA 语言基础
热门文章
- Delphi多线程下的ADO编程
- 数据绑定(七)使用ObjectDataProvider对象作为Binding的Source
- 关于阿里云centos7安装svn,客服端无法链接的问题
- 【Linux】scp“免密” 远程copy较多文件
- centos 6.5 搭建ftp 服务器(vsftpd的配置文件说明)
- QuickReport根据每行的内容长度动态调整DetailBand1的行高
- Android零基础入门第85节:Fragment使用起来非常简单
- MongoDB.Driver 管道 Aggregate
- Spring MVC的工作原理,我们来看看其源码实现
- Hadoop集群(第5期)SecureCRT使用