问题引入
最近遇到一个问题,重构的代码编译报定义的某个宏was not declared in this scope
,但是明明已经引入了包含此宏的头文件。
问题分析(转载内容)
我把问题脱离于项目简单描述一下:我写了一个函数 bool func(ClassA* CA)
需要加到项目中,我就把这个函数的声明放到 head1.h
中,函数参数类型 ClassA
定义在另一个头文件 head2.h
中,因此我需要在 head1.h
中包含 head2.h
;而 head2.h
中之前又包含了 head1.h
,这样就构成了一种头文件相互包含的场景。再加上一些其它的声明与定义,就构成了这样的一个文件结构:
#ifndef __HEAD_1_H__
#define __HEAD_1_H__
#include "head2.h"
#define VAR_MACRO 1
bool func(ClassA* CA);
#endif
#ifndef __HEAD_2_H__
#define __HEAD_2_H__
#include "head1.h"
class ClassA{
int mVar;
void setMem(){ mVar = VAR_MACRO };
...
};
#endif
那么,现在另有两个源文件
#include "head1.h"
#include "head2.h"
整个项目会分别编译这两个源文件,编译完之后会报错,大致意思是 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 };
...
};
#define VAR_MACRO 1
bool func(ClassA* CA);
看到没,这地方 func
函数之前有 ClassA
类型的定义,根本没必要像有些人说的那样加上 ClassA CA
; 这样的前置声明。
我们再展开 source2.cpp
看看:
#define VAR_MACRO 1
bool func(ClassA* CA);
class ClassA{
int mVar;
void setMem(){ mVar = VAR_MACRO };
...
};
这时问题就很清楚了,func
函数声明之前并没有发现 ClassA
类型定义,该定义在函数声明的后面,这时候如果能在head1.h
的函数声明之前加上 ClassA CA
; 的前置声明,就不会在编译的时候报找不到 ClassA
的定义的错误了。
再回到 source1.cpp
展开的源码看看,是不是一下子明白了为什么报找不到 VAR_MACRO
的定义的错误了?修改方法也简单,把宏定义拉到 #include "head2.h"
语句之前就 OK 了。
深入分析
以上为两个文件相互包含引发的问题分析,我所遇到的问题是多文件嵌套,head1.h
中包含head2.h
,head2.h
中包含head3.h
,head3.h
中包含head1.h
。
#ifndef __HEAD_1_H__
#define __HEAD_1_H__
#include "head2.h"
#define VAR_MACRO 1
#endif
#ifndef __HEAD_2_H__
#define __HEAD_2_H__
#include "head3.h"
#endif
#ifndef __HEAD_3_H__
#define __HEAD_3_H__
#include "head1.h"
class CTest
{
...
private:
char m_szName[VAR_MACRO];
}
#endif
当其他文件需要引入head1.h
时,就会有问题了,如source1.cpp
编译之前展开后变为:
class CTest
{
...
private:
char m_szName[VAR_MACRO];
}
#define VAR_MACRO 1
那么VAR_MACRO
可不就是没定义吗。头文件多层相互包含更隐蔽,更难排查。通常遇到此种情况,在代码中全局搜索报错的那个头文件(head3.h
),向上梳理包含关系,梳理到报错的宏(VAR_MACRO
)定义的头文件(head1.h
)。即可定位出问题。
问题延伸
归根到底还是要进行代码文件的规划与梳理来避免此类问题。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)