变量定义的注意事项
我们在写代码的过程中经常会出现变量被重复定义了,我们就做一个小测试,看看这么避免这个问题,什么时候出错。
1. 普通变量重复定义
假设在有三个文件a.h, b.cpp, c.cpp.
//a.h
int i = 123;
//b.cpp
include “a.h”
//c.cpp
include “a.h”
这时候会出现重复定义错误,原因出自编译的时候,.h文件会被展开,两个.cpp文件会被变成
//b.cpp
int i = 123;
//c.cpp
int i = 123;
错误出自链接时,发现定义了两个变量定义在全局数据区,显然重复定义。
如果没有a.h,只有两个cpp的话,可以通过下面的方式避免重复。
//b.cpp
extern int i = 123;
//c.cpp
int i = 123;
这样的话两个i是同一个变量。
有人说pragma once不就是用与解决重复定义的问题吗? 你可以试试看,结果还是错误。
这是因为我们没有弄清楚pragma once的真正用意,一知半解的时候就用了。
假设有两个文件a.h, a.cpp
//a.h
int i = 123;
//a.cpp
include “a.h”
include “a.h”
如果a.cpp被引用两次的话,会出现重复定义的错误, 问题就是i在cpp被展开了两次。
这时候如果加上pragama once或者用预定义宏的话,就可以解决这个问题。
pragma once的主要用途是避免在同一个cpp文件中某一个.h文件被多次展开,特别是在间接引用的时候。
关于我们提出来的第一个问题,我们解决办法之一就是把定义放到.cpp中,如果其他地方引用的话,就用extern方式。 对于普通变量extern 可以放在变量声明处,也可以放在定义处,也可以放在想引用地方,用于告诉编译器,我在程序数据区是唯一的,不要再重新定义一个兄弟了。
2. 关于const变量
根据前面的文章《c++中const的完全解析》,我们知道它是放在符号表中的,
//a.h
const int i = 123;
//b.cpp
include “a.h”
//c.cpp
include “a.h”
只维护一个在符号表中的变量,展开相当于
//b.cpp
const int i = 123;
//c.cpp
extern const int i; //这里面有一个小问题我在下面会提到
所以就不会出现重复定义的问题。
但是如果const变量是定义在.cpp文件中的呢,我们都知道用extern就可以了,假设有两个文件a.cpp,b.cpp。
//a.pp
const int i = 123;
//b.cpp
extern const int i;
但是编译的时候会出错,如果在a.cpp中补一个extern就可以了,如下
//a.pp
extern const int i = 123;
//b.cpp
extern const int i;
3. 关于static变量
根据文章《C++中Static的完全解析》,static变量是放在全局static数据区的。而且它有唯一性和长期性两个特性。
//a.h
static int i = 123;
//b.cpp
include “a.h”
//c.cpp
include “a.h”
这样的用法也是正确的,不会出现重复定义现象。
如果static变量被定义到.cpp文件中,这时候改变量就活动范围就只是这个 cpp文件了,它不能通过extern被其它.cpp文件引用到。