彻底理解C++在.h头文件中定义变量导致 multiple definition |
您所在的位置:网站首页 › 定义变量包括什么 › 彻底理解C++在.h头文件中定义变量导致 multiple definition |
说明:出现这个错误,请你先检查重复定义的变量是否是定义在了.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” 1.引言学习计算机那么久了,也编程这么久了,但是一直都没有彻底弄清楚头文件互相包含时,为什么有时候会出错,出现重复定义,有时候确又能够正常编译链接,今天仔细研究了一下这个问题,将结论记录下来。 2.编译编译,大家都知道,最后就会产生一个.o文件,我以前估计就理解到这个水平。于是我常常想不通一个问题,比如MFC的一个大工程,里面有a.cpp,a.h,b.cpp,b.h,那他们是合在一起编译吗?那互相包含会不会出错? 结论:编译是针对一个文件来说的,比如有a.cpp,a.h,b.cpp,b.h,他们之间的编译是没有关系的,a.cpp和a.h会产生一个a.o,他的编译和b完全没有关系,同样b.cpp和b.h产生的b.o和a也没有关系(除了include包含的情况)。 3.链接链接就很有可能是很多.o文件一起链接,组成一个可执行文件,例如g++ a.cpp b.cpp -o c,这样就是先单独编译了a.cpp和b.cpp并将产生的a.o,b.o链接为c 4.头文件包含的问题我们都知道,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.h和b.h当中都会展开,而不是说a和b因为是一个工程,所以只展开一次。 5.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的定义了 而b.cpp b.h也是被单独编译的,产生b.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.h和stdafx.cpp产生stdafx.o文件,然后我们的a.cpp编译的时候包括了stdafx.h,但是stdafx.h里面只有extern a,这就说明,我们在下面使用到的a都是在其他文件中定义的,同样的b.cpp编译时,也不会定义a,所以编译出来的a.o和b.o都不包含a的定义。最后链接,链接的时候,由于这是一个工程,所以mfc会把stdafx.o,a.o,b.o链接在一起,这样我们的a就定义了一次,在stdafx.o中。 看到这里,你可能会觉得奇怪,我都不知道我按下vc6.0的编译按钮,是编译了那么多文件,按下链接按钮,又是把所有文件链接到一起了,这些可能需要进一步了解makefile之类的东西。 6.结论1.编译是针对一个一个文件来说的,而链接则是针对一个工程所有的.o文件而言的。 2.#ifndef只是对防止一个文件的重复编译有效 3.全局变量最好在.cpp文件中定义,在.h文件中加上extern申明,因为在.h文件中定义,容易在链接时造成变量重定义。 4.注意mfc中会自动编译stdafx,并将stdafx.o加入到工程中一起链接. |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |