如何理解头文件?

来源:互联网 发布:bt网站推荐 知乎 编辑:程序博客网 时间:2024/04/30 02:01

头文件是什么?只要有一点C语言基础的小伙伴应该都知道,这个都不用我解释了,一般都是跟#include这个保护预编译指令合在一起。


对于刚开始编程的小伙伴,理解C语言基本也没有什么问题,但是怎么才能写一个比较通用、正确的头文件,不是所有的刚编程的人都知道,甚至有相当编程经验的人也可能写不出正确通用的C/C++头文件。下面我们就来侃一下这个问题。


一,头文件里面放什么东东
头文件本质上是一种偷懒技术,一个稍微复杂点的程序少不会出现多个文件,对我们来说,哪怕是写一个hello world,看似只有三四行代码,其实对编译器来不然,比如你的printf函数编译从你的源码中是找不到的,所以你就把stdio.h这个头文件包含进来,因为那里面有这个函数的原型说明。由于这个头文件里面包含了许许多多都是编程非常常用的数据结构和函数,说人家就给我写好到一个文件里面stdio.h,不需要我们自己去写了,这样我们就偷懒省时间了,要是你精力充沛,你可以不要这个头文件,把用到的函数原型在你的源代码文件前声明一下就可以不要stdio.h这样的头文件了。


也就是说,如果有数据结构、函数原型声明、全局变量声明等等这些可能被其他文件使用到的东东,都可以放到一个头文件里面,共自己或别人使用。其实这个也是是否放到头文件里面的标准,同样是结构体定义,同样是函数原型声明,哪些需要放头文件,哪些不需要,就看是否可能被其他文件引用了。其实#include包含的不一定非得是头文件,还可以是源文件,数据等,只要是预编译后合法的东西都是可以的。


二,防止重复包含
既然头文件可能被其他文件包含的东西,就意味着同一个头文件可能会被多个源文件包含,就不可避免在一个源文件中出现多次包含到同一个头文件的情况。比如a.h被b.h和c.h包含,而d.c同时需要包含b.h和c.h,结果d.c就间接包含了两次a.h,这样就出现了重复包含,如果直接这样编译一定会出现重复定义的问题。所以需要 增加防重复定义的机制,这个就是靠如下的通用办法来解决:


#ifndef __XXXX_H__
#define __XXXX_H__

....

#endif


就是通过是否定义了一个__XXXX_H__来检查是否已经被包含,如果没有包含就定义一个__XXXX_H__的宏,并且把中间的东西包含进去,否则就什么都没有包含。这个宏的名字__XXXX_H__你可以任意取你喜欢的,但为了防止这个不要取成已有的宏定义,一般就是头文件名字就好了。


注意到以上的重复定义控制,基本的头文件就没有什么问题了。


三,增加C++编译器编译C库函数机制
如果你的编译器是C++编译器,而调用的函数是一个C编译器生成的库,那么就需要增加这个机制,否则会编译后链接会提示找不到函数。由于你不能保证你的头文件只是用在C编译器下,所以加上这个是明智的。为了在C++编译器下正确链接到C库函数,需要在C库引出的头文件函数和变量中加入extern "C"这个声明,如果函数和变量比较多,你可以用括号括起来,不用麻烦在每一个前面加了。


extern "C" {
...
}


要是我们的编译器本来就是C的编译器就不需要这个了,那怎么区分别人的编译器到底是C还是C++的呢?于是所有C++编译器统一了一个宏定义__cplusplus(注意是两个下划线字符)来区分本编译器是否是C++编译器,如果是就定义这个宏,否则就不定义。于是上面的可以改成:


#ifdef __cplusplus
extern "C" {
#endif

... //c export function and varibles

#ifdef __cplusplus
}
#endif


四,通用的C/C++头文件模板
有了以上的基础,我们可以写出正确、通用的C/C++头文件了,假如我们要写一个myhead.h头文件,下面就是一个通用的头文件模板:


#ifndef __MYHEAD_H__
#define __MYHEAD_H__

#ifdef __cplusplus
extern "C" {
#endif

...
...//c export function and varibles
...

#ifdef __cplusplus
}
#endif

#endif //__MYHEAD_H__

0 0
原创粉丝点击