C头文件相互包含

今天遇见一个很头疼的事,就是1.h头文件包含2.h,但是1.h里面却找不到2.h定义的一个结构体变量。最后排查发现是2.h里面又包含了1.h导致的。

C语言中头文件包含的处理原则

之前一直以为,一个.c文件对应一个.h文件,比如hello.c对应着hello.h。hello.c文件只需要包含它自身的hello.h头文件。若hello.c文件中用到其他文件中的内容,比如yebo.h,则hello.h文件把用到的头文件yebo.h包含进来就可以了。好像自己一直秉承这个理念进行代码编写。

工程文件数量小时,这种理念貌似看不出问题,但随着工程文件数量越来越多,我发现自己这种思路有了弊端:头文件互相包含,导致编译时自以为有些宏变量声明了,它就能起作用,但实际测试发现这种方式编码后,有些声明的宏没能起到作用。(.h文件我采用了避免重复包含的#ifndef __**_H__ #define __**_H__的写法)

正确的做法是:应该秉承.c文件对应的.h文件只包含头文件里用到的其它文件的头文件,任何非必须的.h文件不要包含;而.c文件里面要包含用到的所有.h文件。这样写即使存在.c文件内头文件重复包含也不伤大雅。

我发现我遇见的问题,实际上和这位博主写的差不多:C语言头文件相互包含的问题

问题:

头文件交叉包含是否会导致递归包含,导致编译出错?
如果不会因为递归包含出错,那么交叉包含是不是完全没问题?

1.头文件交叉包含是否会导致递归包含,导致编译出错?(无#ifndef)

假若头文件a包含了头文件b、头文件b又包含了头文件a,那么在#include头文件a的时候,就可能会导致递归包含,从而导致编译出错;

/* a.h */
#include "b.h"
#define A_H 1

/* b.h */
#include "a.h"
#define B_H 2

/* main.c */
#include <stdlib.h>
#include <stdio.h>
#include "a.h"
#include "b.h"

void main()
{
    
    
	printf("hello world!\n");
}

在Ubuntu下面使用gcc编译会报错:

a.h:1:15: error: #include nested too deeply
b.h:1:15: error: #include nested too deeply

2.头文件交叉包含是否会导致递归包含,导致编译出错?(有#ifndef)
修改a.h、b.h两个文件,main.c文件内容不变。此时编译正常通过:因此可以知道,当头文件相互包含时,只要有预处理#ifndef就可以保证理论上不会出错。

/* a.h */
#ifdef __A_H_
#define __A_H

#include "b.h"
#define A_H 1

#endif

/* b.h */
#ifndef __B_H_
#define __B_H

#include "a.h"
#define B_H 2

#endif

/* main.c */
#include <stdlib.h>
#include <stdio.h>
#include "a.h"
#include "b.h"

void main()
{
	printf("hello world!\n");
}

3.如果不会因为递归包含出错,那么交叉包含是不是完全没问题?

从上面的头文件内容可以看出,虽然两个头文件相互包含,但是两个头文件内容并不相互引用。因此编译不会出现问题。但是如果像下面文件,头文件变量又相互引用,则编译会出现变量未知错误

/* a.h */
#ifndef __A_H_
#define __A_H_
#include "b.h"

typedef struct _A_H{
    
    
	int a;
} A_H;

int fun(B_H *ptr);

#endif

/* b.h */
#ifndef __B_H_
#define __B_H_
#include "a.h"

typedef struct _B_H{
    
    
	A_H b;
} B_H;

#endif

/* main.c */
#include <stdio.h>
#include "b.h"
#define CC DD
#define DD 2

void main()
{
    
    
	printf("hello world!\n");
}

在Ubuntu下面使用gcc编译会报错:

a.h:9:9: error: unknown type name ‘B_H’

总结

头文件相互包含,而且变量又相互引用。此时应该将其中一个头文件拆成两个头文件b1.h、b2.h,b1.h让原来的a.h包含;b2.h用来包含a.h。不要使两个头文件变量相互引用引用的设计方式出现。

猜你喜欢

转载自blog.csdn.net/weixin_42581177/article/details/128841463
今日推荐