您的位置:首页 > 编程语言 > C语言/C++

C/C++ 中头文件相互包含引发的问题

2016-11-19 13:59 239 查看
http://blog.csdn.net/chen_yi_long/article/details/8615643

C++中的#include 放在头文件中还是放在cpp文件中? ------- http://blog.sina.com.cn/s/blog_53b45874010177dk.html
h和cpp中同时可以使用include包含头文件, 但尽量不要在.h文件中include非必须的其他.h文件。

也就是说,当.h中的内容(各种声明)用到了T* t那么我们 没有必要 #include "t.h",只需要在。h中 class T; 声明一下即可。

1 常识: A文件修改后,所有依赖A的.cpp都会重新编译《.ilk文件》

3 PC正常,android编译报错报error: duplicate 'unsigned ' 原因 头文件相互包含《即:同一个头文件包含多次》 编译器在编译时:把每个编译单元的.h都展开。so....

4 宏#ifdef用于解决编译时重定义, 无法解决Link。。。。



----------------------------------------------------------------------------------------------------------------------------官方文档:

1 尽量保证在头文件中只声明变量和函数,不要定义。这个很重要,不然链接...变量不定义,函数也不要出现定义,但可以出现声明

2



看框架:IMoblieClientInterface.h头文件。



3 extern声明后,需要使用var时直接include头文件就OK (变量赋值在需要的地方)

今天下午遇到一个头文件相互包含而导致的编译问题,花了我不少时间去调试没找到问题,最后晚上跟师兄讨论不少时间,突然有所顿悟!


问题重现

我把问题脱离于项目简单描述一下:我写了一个函数
bool func(ClassA* CA)
需要加到项目中,我就把这个函数的声明放到
head1.h
中,函数参数类型 ClassA 定义在另一个头文件
head2.h
中,因此我需要在
head1.h
中包含
head2.h
;而
head2.h
中之前又包含了
head1.h
,这样就构成了一种头文件相互包含的场景。再加上一些其它的声明与定义,就构成了这样的一个文件结构:

head1.h

#ifndef __HEAD_1_H__
#define __HEAD_1_H__

#include "head2.h"

#define VAR_MACRO  1          //define a macro, which used in head2.h

bool func(ClassA* CA);        //ClassA is defined in head2.h

#endif


head2.h

#ifndef __HEAD_2_H__
#define __HEAD_2_H__

#include "head1.h"

class ClassA{
int mVar;
void setMem(){ mVar = VAR_MACRO };    //macro VAR_MACRO is defined in head1.h

...     //other members and functions
};

#endif


那么,现在另有两个源文件

source1.cpp

#include "head1.h"

//... some source code


source2.cpp

#include "head2.h"

//... some source code


整个项目会分别编译这两个源文件,编译完之后会报错,大致意思是 ClassA 和 VAR_MACRO 没有定义,那么问题就比较奇怪了,每个头文件都分别引用了另一个头文件,为什么会出现未定义呢?


问题分析

我们都知道 C/C++ 中头文件开始习惯使用
#ifndef ... #define ... #endif
这样的一组预处理标识符来防止重复包含,例如上面的问题中我也使用了,如果不使用的话,两个头文件相互包含,就出现递归包含。这个很好理解就不多叙。

回到问题本身,我在微博上贴出了这个问题,有人说在
head1.h
的函数前加上
ClassA
A;
的前置声明,至于为什么要加,估计很多人都没理解...

对于
source1.cpp
,它包含了头文件
head1.h
,那么在编译之前,在
source1.cpp
中展开
head1.h
,而
head1.h
又包含了
head2.h

那么也展开它,这时
source1.cpp
就变成类似下面这样:

class ClassA{
int mVar;
void setMem(){ mVar = VAR_MACRO };    //macro VAR_MACRO is defined in head1.h

...     //other members and functions
};

#define VAR_MACRO  1          //define a macro, which used in head2.h

bool func(ClassA* CA);        //ClassA is defined in head2.h

//... source1.cpp source code


看到没,这地方 func 函数之前有 ClassA 类型的定义,根本没必要像有些人说的那样加上
ClassA CA;
这样的前置声明。

我们再展开
source2.cpp
看看:

#define VAR_MACRO  1          //define a macro, which used in head2.h

bool func(ClassA* CA);        //ClassA is defined in head2.h

class ClassA{
int mVar;
void setMem(){ mVar = VAR_MACRO };    //macro VAR_MACRO is defined in head1.h

...     //other members and functions
};

//... source2.cpp source code


这时问题就很清楚了,func 函数声明之前并没有发现 ClassA 类型定义,该定义在函数声明的后面,这时候如果能在
head1.h
的函数声明之前加上
ClassA
CA;
的前置声明,就不会在编译的时候报找不到 ClassA 的定义的错误了。

再回到
source1.cpp
展开的源码看看,是不是一下子明白了为什么报找不到 VAR_MACRO 的定义的错误了?修改方法也简单,把宏定义拉到
#include
"head2.h"
语句之前就 OK 了。


问题反思

现在回头想想这个问题,其实是个非常简单的头文件包含的问题,如果了解一些编译器的预编译过程,错误原理也很简单。但为什么我卡在这个问题很长时间,原因有以下几点:

问题出现在一个项目的编译过程中,未能准确地定位问题的原因
出现问题,没有静下来心来理清问题,C/C++ 编译基础知识点虽然知道,但未能第一时间运用到该问题的分析上
师兄说加上前置类的声明,确实解决了类类型找不到的错误,虽然有问题解决方法,但没有真正理解这种做法的道理,以至于宏定义找不到的错误还是不知如何去解决(其实本质是一样的)

总的来说,遇到问题不要慌,保持大脑清醒,把加一行或减一行代码期望就能碰运气编译通过的时间拿来分析问题更有效,解决问题之后一定确定自己是否知其然亦知其所以然!

---------------------------------------------------------------------------------------------------------------





原因 头文件相互包含《即:同一个头文件被包含多次》 所以重复包含最经常带来错误就是重定义

-----------------------------------------------------------------------------------徐libin: 头文件相互包含...

例子:1 WinDef.h中的chair非法chair



例子2: eclispe编译报错办法: 把多次引用的Da_majiangProtocol.h和stAniQueue挪到别的文件Appdele.h中



头:build报错, 在编译SingleReceiver。cpp报错,--中包含2个.h---



-------例子:

#include "1.h"

#include "2.h"

#include "3.h"

int main()

{

3个。h中都声明struct/宏; 编译duplicate如何解决:

1 将struct/宏放入一个公共头文件

2 在struct/宏出现使用#ifdefine #endif

}

重定义2种:

1 编译时: 如上面例子

2 Link时: 头文件中有定义实现,导致多个.obj
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: