最新消息:XAMPP默认安装之后是很不安全的,我们只需要点击左方菜单的 "安全"选项,按照向导操作即可完成安全设置。

C语言头文件互锁和包含问题

XAMPP相关 admin 422浏览 0评论
大家好,我是bug菌!
今天带来的主要内容是关于头文件的那些事,或许头文件并不是那么起眼,大部分人在编程中对头文件的组织并没有形成一定的设计思路,虽然使用了一些预编译在一定程度上能够减少重复包含问题,但肆无忌惮的把头文件写得满天飞终究会带来诸多问题。
同样如果你对头文件的设计和组织没有自己的一些想法,或许对程序的模块化、分层设计还没有领悟特别到位吧。
先不把网撒大了,各个击破,不然收不了场,本文主要讲解两个问题C程序编译的大体过程和头文件递归互锁问题。

1

C编译过程

在大部分模块化的设计中,我们都会去设计同名的.h和.c来作为一个模块的封装,那么为了引用到其他模块的一些接口、类型、变量等,会选择在源文件.c的起始位置加上相应的头文件,或者在.c文件已经包含的头文件中添加所要使用的头文件。
1//file driver.c
2//#include “XXXX.h”
3#include “driver.h”
4/****************************
5 * Function : Function
6 ***************************/
7void Function(void)
8{
9    ……
10}
1//file driver.h
2#ifndef __DRIVER_H__
3#define __DRIVER_H__
4
5//#include “XXXX.h”
6
7
8
9
10#endif
然而头文件的使用会给人一些错觉,比如你会觉得在编译C文件的时候一些函数的调用会被函数的实现替换,或者认为.h文件也跟C文件一样进行编译等等之类的。
如果有诸多的疑问,那还是要有跟着bug菌走一遍C程序的编译过程,这个过程大部分人也能够朗朗上口 : 预编译-编译-汇编-链接,那这里主要说说特别需要注意的:
drf0010
前面的三个过程都是以每个源文件.c文件为核心来进行处理的,并不是存在什么函数的替换、转移等等。
预编译主要是对源文件中的头文件,宏定义、预编译符等等进行展开和替换,不会设计到源文件与源文件的交换。
编译也是以每个C文件为核心,进行语法上的分析与检查,并把C文件转化为汇编文件。
汇编过程就是把编译过程生成的汇编程序进一步转化为与平台相关的机器码,最终获得目标文件,同样该过程也不会有C文件之间的交换。
最后的链接过程,由于目标文件中含有非常多变量信息、函数等信息,链接器根据链接脚本等,进行目标文件的分析与整合最终生成可执行文件。
在编写代码的过程中去思考这个过程的朋友估计不太多,一个最常见的现象:有些人的工程改一处代码整个工程都得重新编译,而有些工程却不需要,其实这就是一个文件的关联问题。
drf00010
在最开始写代码的时候一个C文件写到头,应该不少人这么做过吧。代码中充斥着各种函数的定义和声明,并且当你调用一个函数或者使用变量的时候,还得前面一定要有相应的定义或者声明。
所以把一个文件分成多个文件,把声明等等大部分都放到了相应的头文件中供使用,仅仅只是为了代码更好的管理、编译和设计。
你会一句话总结一切为了模块化设计,然而我想温柔的对你说,难道一个源文件就不能模块设计吗?模块化设计可不是分几个文件那么简单。

2

互锁问题

对于头文件互锁问题引起的原因,一方面是头文件滥用导致的,另外一方面还是因为功能结构层次设计上存在问题。
大部分都要感谢头文件里面这几条预编译:
1//file XXXX.h
2#ifndef __XXXX_H__
3#define __XXXX_H__
4#endif
如果没有这几个预编译估计很多人写代码要难受死了,它主要是为了减少头文件的重复包含问题,大部分重复包含的头文件都幸免能够编译通过。
但是它无法解决有一类包含–递归包含
头文件的递归包含就是两个或者多个头文件,”你中有我,我中有你”,最终谁也分不清楚是庄周梦到了蝴蝶,还是蝴蝶梦到了庄周。
来上代码看一下:
参考伪代码:
1//file driver1.h
2#ifndef __DRIVER1_H__
3#define __DRIVER1_H__
4
5#include “driver2.h”
6
7typedef struct _tag_Obj1
8{
9    ……
10}stObj1;
11
12void FunctionObj1(stObj2 *pObj);
13
14#endif
1//file driver2.h
2#ifndef __DRIVER2_H__
3#define __DRIVER2_H__
4
5#include “driver1.h”
6
7typedef struct _tag_Obj2
8{
9    ……
10}stObj2;
11
12void FunctionObj2(stObj1 *pObj);
13#endif
这样的结构编译器会提示相应的结构体没有定义,你可以在源文件中展开然后逐个往前找相应的结构体定义,最终形成了一种递归形式的包含问题。
你应该会在相应的.c文件中尝试着调整头文件的位置,而并不会有所改善。
解决此类问题的办法有很多,比如把两个头文件直接整合成一个头文件等,常用的都是抽出公共部分单独成为一个头文件,这样程序的层次更加鲜明。

所以头文件的设计也就在一定程度上决定了你的程序设计架构,所以很多人学习一些大的开源程序都是从头文件入手把脉整个设计~

— EOF —

转载请注明:XAMPP中文组官网 » C语言头文件互锁和包含问题

您必须 登录 才能发表评论!