变量定义在.h头文件导致 multiple definition of

为尊重原创以及版权的要求,本文转载自【C++】变量定义在.h头文件导致 multiple definition of 的解决方法和根本原因。在此基础上,写此博文记录知识点并划重点。

说明

出现这个错误,请你先检查重复定义的变量是否是定义在了.h头文件中,如果是,请您耐心的看完这篇文章,他会告诉你错误的根本原因。
如果你很着急,不想弄清楚原因,请直接按下面的方法更改:
假设重复定义的变量是int a,且你定义在了b.h,想作为全局变量使用,那么:
1.删除b.h中的int a;
2.在b.cpp中加入a的定义int a;
3.在b.h中加入 extern int a;
4.在要使用a的cpp文件中加入#include “b.h”。

一、编译

编译,大家都知道,最后就会产生一个.o文件,我以前估计就理解到这个水平。于是我常常想不通一个问题,比如MFC的一个大工程,里面有a.cpp,a.h,b.cpp,b.h,那他们是合在一起编译吗?那互相包含会不会出错?

结论:编译是针对一个文件来说的,比如有a.cpp,a.h,b.cpp,b.h,他们之间的编译是没有关系的,a.cppa.h会产生一个a.o,他的编译和b完全没有关系,同样b.cppb.h产生的b.oa也没有关系(除了include包含的情况)。

二、链接

我们都知道,ifndef是为了防止头文件重复包含,比如

a.h:
#include "b.h"
#include "c.h"

b.h:
#include "c.h"

c.h:

这样的话,我们编译a.cpp肯定会出现问题,因为a.h里面包含了2次c.h,而c.h里面没有加入#ifndef之类的语句
所以可以将c.h改为下面的形式:

c.h
#ifndef _C_HEADER
#define _C_HEADER
...
#endif

这样的话,编译a.cpp就没错了,但是我们要注意,#ifndef只是针对某一个文件,而不是一个工程。比如你在a.h里面包含了c.h,在b.h里面也包含了c.h,这样不管你的c.h有没有加入#ifndef,你的c.h文件在a.hb.h当中都会展开,而不是说因为ab是一个工程,所以只展开一次。

三、extern的用法

首先,头文件.h中不适宜定义变量,我们都知道定义全局变量的常规使用方法是在.cpp文件中定义变量,在.h文件中用extern申明,这是为什么呢?看下面的例子:

比如在MFC的一个大工程中,我想定义一个全局变量int a,因为所有的文件都包含stdafx.h,我们考虑写在里面:

stdafx.h:
int a
------------------------
a.cpp:
#include "stdafx.h"
extern int a;
a = 100;
-----------------------
b.cpp:
#include "stdafx.h"
extern int a;
a = 200;

编译没错,但是链接错了!a重复定义。
原因:在编译的时候,由于是一个文件为单位,所以 a.cpp、a.h被单独编译产生a.o。这样在链接的时候,由于他包含了stdafx.h,所以在a.o中,已经有int a的定义了。
正确写法:

stdafx.cpp:
int a;
-----------------------
stdafx.h:
extern int a
------------------------
a.cpp:
#include "stdafx.h"
a = 100;
-----------------------
b.cpp:
#include "stdafx.h"
a = 200;

在编译的时候,由于mfc会自己默认编译stdafx.hstdafx.cpp产生stdafx.o文件,然后我们的a.cpp编译的时候包括了stdafx.h,但是stdafx.h里面只有extern a,这就说明,我们在下面使用到的a都是在其他文件中定义的,同样的,b.cpp编译时,也不会定义a,所以编译出来的a.ob.o都不包含a的定义。
再链接的时候,由于这是一个工程,所以mfc会把stdafx.o,a.o,b.o链接在一起,这样我们的a就定义了一次,在stdafx.o中。

四、结论

1.编译是针对一个文件来说的,而链接则是针对一个工程所有的.o文件而言的。
2.#ifndef只是对防止一个文件的重复编译有效。
3.全局变量最好在.cpp文件中定义,在.h文件中加上extern申明,因为在.h文件中定义,容易在链接时造成变量重定义。
4.注意mfc中会自动编译stdafx,并将stdafx.o加入到工程中一起链接。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值