欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

聊聊C语言的.h文档

程序员文章站 2022-04-01 20:08:54
我看过的C语言教科书都在谈语法,千篇一律,好像是互相抄的,没有认真体合初学者的烦恼。众多的C语言书都集体忘记谈头文件的事情。 上课的话可以请教老师,将书本没有知识补全。自学的孩子...

我看过的C语言教科书都在谈语法,千篇一律,好像是互相抄的,没有认真体合初学者的烦恼。众多的C语言书都集体忘记谈头文件的事情。

上课的话可以请教老师,将书本没有知识补全。自学的孩子伤不起。我就是这样一个自学的孩子。好在网上有好多热心人写博客,也能从中学到一丁点儿,更多的要自己看代码,自己写,自己明悟。这过程有点慢,所以我将人家没写的部分也补一下。

H文件也叫头文件,是C语言的一种接口。可以连接别的C文件或者程序库(LIB),连接了就可以使用,能够使用什么就写在h文件上。另外也有只写公用定义和公用宏到h文件,这就只用于统一定义而尔,并不连接什么。

如果没有听明白,那么就看看用法吧。我总结出h文件的4种用法。(我说的单片机以51为主,谈的编译器就是Keil4)

用法1:调用编译器的程序库。

编译器的程序库就在LIB就在C:\Keil_v4\C51\LIB,我们只要到INC文件夹(C:\Keil_v4\C51\INC)里同面找h文件,右击编辑,就用记事本打开,可以看到能调用的函数。例如想用Sin(),它就在math.h里面。我们不用知道对应的LIB是哪一个,它总是在LIB文件夹里就行。我们只要在C文件头项上写一行#include 就这样便可以在你的这个C文件里使用Sin()。

是不是很简单。我们要注意,要写成,这大小写不重要,写成也一样行,但是不要写成"Math.h",不要用双引号。不急,后面会说到双引号的。<>表示这个h文件就是Keil的INC文件夹。如果是INC里面的文件夹内h文件,例如C:\Keil_v4\C51\INC\Atmel下面的89c51rd2.h,要写成。

用法2:调用编辑器的一些定义或宏。

关于编译器的事用法1说过的,就不多说,例如在FLOAT.H,里面并没有什么函数可用,但是它定义了一些宏。如果有需要调用里面的,就跟用法1一样就行。

用法3:调用别的C文件里面的函数和变量。

这是我们最常用到的。我们从网上找到一些源代码,将它们分离出来一些C文件来使用;我们要整理我们的源代码,分门别类的归纳到不同的C文件里面去。

网上找到的代码也不能"不明不白"的使用,要先看个明白才能用呀;就像我们自己写的一样。那我就拿我们自己写的代码来说吧。例如我们写了一个驱动1602屏的代码,里面有1602初始化,又有读数据函数,又有写数据函数等等。我觉得这代码写下来太臃肿了。我们可以将所有关于1602的代码剪切到一个空白的1602.c文件里面。main.c文件里立马少了好多,整个代码都清爽了。但是main.c要怎么调用1602.c呢?

第一步,是将1602.c放到工程里面。

第二步,是写1602.h文件。方法是找出1602.c里面,可以让main.c用到的函数,(有些是1602.c内部用的函数,外部无需调用,那就排除)将找到的函数原型写到1602.h文件里面。还有就是如果参数或返回值用到了某些自定义结构体,或联合等,都要写上它们的定义,如果这些定义是在某个h文件里,则要包含这个h文件。

我建议在1602.c文件里也写上一行 #include"1602.h",作用是:(1)1602.c里面的函数能从1602.h找到自己调用的函数,例如初始化Init1602()就需在调用1602的写指令(建议没有写到xxx.h里去的内部函数都写到xxx.c文件的最前头。因为每一个函数找自己调用的函数时,都是向上找的。找到xxx.h文件则进入xxx.h文件里面找)(2)参数或返回值用到了某些自定义结构体,或联合等,这定义h文件上需要,C文件上同样需要,那么这样就可省出在C文件重新写一次的麻烦。

很多情况下会出现h文件的循环包含。这会出乱子的。我们在写h文件时都会写一个条件编译。例如math.h会有这样的结构:

#ifndef __MATH_H__

#define __MATH_H__

...math.h的真正内容

#endif

/////////////////////

那么1602.h

即可以写上

#ifndef __1602_H__

#define __1602_H__

...1602.h的真正内容

#endif

这意思是说,如果没有定义__1602_H__,那就定义__1602_H__,同时也编译1602.h的内容。下一次再碰到1602.h,因为__1602_H__已经定义过了,不会再一次编译1602.h。这就免了重复编译1602.h,那么循环包含也不会出乱子了。

第三步,将1602.h包含到main.c里面就行了。

在mai.c的顶上写一行#include"1602.h"就OK。这要说说为什么用双引号。用双引号表示这个h文件在工程文件夹里。

第四步,在工程里指定H文件的所在。

打开Keil4的“为目标xxxxx设置选项”窗口,或点击

。再打开C51页,点Include Paths(意思是包含路径)最右侧的...按扭,在Folder Setup窗口里面就可以管理 "工程里全部双引号h文件" 所在的文件夹。新增删除,我就不用多说了。总之,这里必然有1602.h所在的文件夹,才能在工程里使用1602.h;否则编译时就报错说,缺少1602相关函数的原型。到这里就完成了。

其它的代码也可以这样整理。不光是代码清爽了。以后这些整理出来的代码还可以重用,用在以后的程序里。好处是写好了,测试好了,就不用再多看一眼,肯定没有Bug。只管用就好了。

用法4:调用公用定义和公用宏。

例如我喜欢用u8来代替unsigned char,(typeunsigned char u8;)写程序超方便。还有很多定义,适合代码移植,那么我将写到一个h文件里。又例如,我定了一个二进制的运算宏,我程序很多地方要用到。那么我就可以写一个h文件里。使用方式跟用法3是一样的。

有些人会疑问:xxx.h必须跟对应的xxx.c同名吗?答案是:没有要求同名。只是同名的话好管理。

又有人会问:一个h文件只能对应一个c文件吗?答案是:可以对应多个的。只要这些C文件都在工程里。当然不同C文件里的函数不能重名呀。

当然,关于h文件还有更多的疑问,这里不多说,我怕写多了,理解不了。先到这里。

维京猎人 2017-8-23