C语言丨使用#ifndef结构防止对头文件重复包含

昨天某鱼尝试把自己写好的整合版大作业拆成分模块版,却遇到了一些问题。我一看,发现她没有使用#ifndef等宏定义避免对头文件的重复包含。这里是一些详细的解释。

1.问题

为了方便测试,我新建了一个项目,该项目最初包含三个文件:

  1. main.c
  2. a.c
  3. a.h

三个文件内容如下:

main.c

#include <stdio.h>
#include <stdlib.h>
#include "a.h"
 
/* run this program using the console pauser or add your own getch, system("pause") or input loop */

int main(int argc, char *argv[]) {
	printf("in main.c !\n"); 
	test(); //在a.h声明,在a.c定义 
	printf("N = %d\n",N); //420
	printf("a = %d\n",a); //608
	printf("b = %d\n\n",b); //728
	return 0;
}

a.c

#include <stdio.h>

void test(void)
{
	printf("test()!\n");
}

a.h

#define N 420

int a = 608;
int b = 728;

void test(void);

a.h是头文件,其中存放了常量N与变量ab的定义以及test函数的声明。a.c文件则存放了test函数的定义。

对项目进行编译运行,没有遇到什么问题,输出结果如下

in main.c !
test()!
N = 420
a = 608
b = 728

接着,我们向项目中添加一个头文件b.h

#include "a.h"
#define t(x) test(x)

并在main.c中加一行:#include "b.h":

#include <stdio.h>
#include <stdlib.h>
#include "a.h"
#include "b.h"
 
/* run this program using the console pauser or add your own getch, system("pause") or input loop */

int main(int argc, char *argv[]) {
	printf("in main.c !\n"); 
	test(); //在a.h声明,在a.c定义 
	printf("N = %d\n",N); //420
	printf("a = %d\n",a); //608
	printf("b = %d\n\n",b); //728
	return 0;
}

看起来似乎没什么问题。但重新编译运行,报错:
在这里插入图片描述
根据编译器的提示信息,error在于对变量a进行了重复定义。

2.分析

接下来我们分析一下问题产生的原因。

首先来回忆一下#include的用法。这是一条预处理指令,而编译之前预处理器会首先对文件进行扫描, 当发现#include指令后,就会寻找指令后面<>""中的文件名,并把这个文件的内容包含到当前文件中。被包含文件中的文本将替换源代码文件中的#include 指令, 就像你把被包含文件中的全部内容键入到源文件中的这个位置一样。

main.c文件中,我们同时使用了以下两条指令:

#include "a.h"
#include "b.h"

也就是说,我们同时将a.hb.h的全部内容嵌入到了main.c的这个位置。但是,在b.h文件中,也包含一条预处理指令:

#include "a.h"

这条指令再次将a.h文件中的全部内容嵌入到了main.c的这个位置,相当于在main.c中嵌入了两次a.h。而a.h文件中包含对变量a的定义:

int a = 608;

于是,a就被重复定义了两次,引起报错。

3.解决(使用#ifndef结构)

解决方法很简单,使用#ifndef结构(Macro Guard)

#ifndef <标识>
#define <标识>
 ......
#endif

<标识>在理论上来说可以是自由命名的,但每个头文件的这个“标识”都应该是唯一的。标识的命名规则一般是头文件名全大写,前后加下划线,并把文件名中的”.”也变成下划线,如: a.h

#ifndef _A_H_
#define _A_H_
 ......
#endif

在被包含过一次之后,宏_A_H_已经有了,下次再碰到就会略过从#define _A_H_开始到#endif之间的代码。

修改后的main.c文件:

#include <stdio.h>
#include <stdlib.h>

#ifndef _A_H_
#define _A_H_
#include "a.h"
#endif

#ifndef _B_H_
#define _B_H_
#include "b.h"
#endif
 
/* run this program using the console pauser or add your own getch, system("pause") or input loop */

int main(int argc, char *argv[]) {
	printf("in main.c !\n"); 
	test(); //在a.h声明,在a.c定义 
	printf("N = %d\n",N); //420
	printf("a = %d\n",a); //608
	printf("b = %d\n\n",b); //728
	return 0;
}

修改后的b.h文件:

#ifndef _A_H_
#define _A_H_
#include "a.h"
#endif

#define t(x) test(x)

此时重新编译运行,不再报错,输出如下:

in main.c !
test()!
N = 420
a = 608
b = 728
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值