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

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

问题重现

我把问题脱离于项目简单描写叙述一下:我写了一个函数 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 了。

问题反思

如今回头想想这个问题。事实上是个非常easy的头文件包括的问题。假设了解一些编译器的预编译过程,错误原理也非常easy。

但为什么我卡在这个问题非常长时间,原因有下面几点:

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

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

參考资料

Google找了一圈。没找到有价值的资料....

时间: 2024-10-02 23:09:31

C/C++ 中头文件相互包括引发的问题的相关文章

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

今天下午遇到一个头文件相互包含而导致的编译问题,花了我不少时间去调试没找到问题,最后晚上跟师兄讨论不少时间,突然有所顿悟! 问题重现 我把问题脱离于项目简单描述一下:我写了一个函数 bool func(ClassA* CA) 需要加到项目中,我就把这个函数的声明放到 head1.h 中,函数参数类型 ClassA 定义在另一个头文件 head2.h 中,因此我需要在 head1.h 中包含 head2.h:而 head2.h 中之前又包含了 head1.h,这样就构成了一种头文件相互包含的场景.

C程序中头文件相互包含精华(转载)

C程序中头文件相互包含精华(网摘小结) 收藏(转自:http://blog.csdn.net/lingyun3429/archive/2010/04/27/5535191.aspx).h中一般放的是同名.c文件中定义的变量.数组.函数的声明,需要让.c外部使用的声明. 1)h文件作用 1 方便开发:包含一些文件需要的共同的常量,结构,类型定义,函数,变量申明: 2 提供接口:对一个软件包来说可以提供一个给外界的接口(例如: stdio.h). 2)h文件里应该有什么 常量,结构,类型定义,函数,

c中头文件在cpp文件里引用和.h文件引用的思考

我们在编敲代码中头文件是常常使用的. 可是头文件是应该包括在.H文件里还是在.cpp文件里.在这个其中有什么样去差别呢. 假如说我们编写了一个a.cpp  .我们将a.cpp文件的变量和函数申明在a.h中. 在a.h文件有使用了b.中定义的类型type1数据m_type,相同b.cpp的头文件一些变量也声明在b.h中. 此时我们当然能够在a.cpp中包括b.h 也能够在a.h中.这样都是可行的.由于我们编译的时候会会将b.h包括进来. 而.h文件是不參与编译的.然后我们继续深入. 假如我们将b.

C++中头文件与源文件的作用详解

一.C++ 编译模式 通常,在一个 C++ 程序中,只包含两类文件―― .cpp 文件和 .h 文件.其中,.cpp 文件被称作 C++ 源文件,里面放的都是 C++ 的源代码:而 .h 文件则被称作 C++ 头文件,里面放的也是 C++ 的源代码. C++ 语言支持"分别编译"(separatecompilation).也就是说,一个程序所有的内容,可以分成不同的部分分别放在不同的 .cpp 文件里..cpp 文件里的东西都是相对独立的,在编译(compile)时不需要与其他文件互通

C++ 头文件相互包含的问题

今天在看C++ Primer第7章,一个习题是要写两个类,一个是Screen类,一个Window_mgr类,其中,Window_mgr类包含有一个vector<Screen>类型的成员 和一个clear函数,用于操作Screen类,所以需要把clear函数声明为Screen类的友元函数,这样就需要在定义Screen类的头文件中包含Window_mgr类的头文件,同理也需要在Window_mgr类中包含Screen类的头文件,如下: Screen.h #ifndef SCREEN_H #defi

c中头文件在cpp文件中引用和.h文件引用的思考

我们在编写程序中头文件是经常使用的.但是头文件是应该包含在.H文件中还是在.cpp文件中.在这个当中有什么样去区别呢.  假如说我们编写了一个a.cpp  .我们将a.cpp文件的变量和函数申明在a.h中.在a.h文件有使用了b.中定义的类型type1数据m_type,同样b.cpp的头文件一些变量也声明在b.h中.此时我们当然可以在a.cpp中包含b.h 也可以在a.h中.这样都是可行的,因为我们编译的时候会会将b.h包含进来.而.h文件是不参与编译的.然后我们继续深入.假如我们将b.h文件定

C++中头文件设计

对于小工具程序而言,用C++编写估计也就几个文件,此时很少设计头文件互相包含引发的编译出错问题.但是当软件功能越来越多,功能越来越复杂,各模块之间的调用关系也越来越不明显,此时很有可能会出现A头文件包含B头文件,B头文件包含A头文件的情况,这种互相包含头文件会导致出现找不到编译类型的错误.最简单的代码如下:A.h如下 #include "B.h" class A { B b; } A.cpp如下 #include "A.h" class A { ... } B.h如

Makefile中头文件在依赖关系中作用

摘于:http://bbs.csdn.net/topics/120024677 (1)在makefile的依赖关系中用不用体现.h头文件?(2)如果在依赖关系中要体现.h头文件,应该体现到什么层次?==============================(1)在makefile的依赖关系中用不用体现.h头文件?============================== 下面是我的一些认识: 头文件中定义的是接口(函数接口,文件外全局变量和宏定义),它的作用是向调用文件封装函数的实现过程.在

头文件相互包含出错问题解决

今天写程序遇到了一个问题,花了好几个小时各种找资料都没有解决,终于皇天不负有心人还是让我给把它kill 掉了.什么问题呢?那就是头文件相互包含出错(当然之前我并不知道是这个原因),先来看代码: Test1.h #include "cocos2d.h" #include "Test2.h" class Test1 : public Layer {     ----     Test2 *test2; }; Test2.h #include "cocos2d.