C语言文件包含与头文件写法
- 格式:doc
- 大小:31.00 KB
- 文档页数:5
C语言书写规范指南第1章文件结构每个C程序通常分为两个文件。
一个文件用于保存程序的声明(declaration),称为头文件。
另一个文件用于保存程序的实现(implementation),称为定义(definition)文件。
C程序的头文件以“.h”为后缀,C程序的定义文件以“.c”为后缀。
1.1版权和版本的声明版权和版本的声明位于头文件和定义文件的开头(参见示例1-1),主要内容有:(1)版权信息。
(2)文件名称,标识符,摘要。
(3)当前版本号,作者/修改者,完成日期。
(4)版本历史信息。
/**Copyright(c)2001,吉林大学物理学院无线电*Allrightsreserved.**文件名称:filename.h*文件标识:*摘要:简要描述本文件的内容**当前版本:1.1*作者:输入作者(或修改者)名字*完成日期:2007年7月20日**取代版本:1.0*原作者:输入原作者(或修改者)名字*完成日期:2007年5月10日*/示例1-1版权和版本的声明1.2头文件的结构头文件由三部分内容组成:(1)头文件开头处的版权和版本声明(参见示例1-1)。
(2)预处理块。
(3)函数和类结构声明等。
假设头文件名称为SCL_SPI.h,头文件的结构参见示例1-2。
【规则1-2-1】为了防止头文件被重复引用,应当用#ifndef/#define/#endif结构产生预处理块。
【规则1-2-2】用#include <filename.h>格式来引用标准库的头文件(编译器将从标准库目录开始搜索)。
【规则1-2-3】用#include “filename.h”格式来引用非标准库的头文件(编译器将从用户的工作目录开始搜索)。
【规则1-2-4】#include 后面使用TAB键控制排版。
【规则1-2-5】头文件中只存放“声明”而不存放“定义”【规则1-2-6】全局变量在头文件中声明,在.c文件中定义.h extern in tvalue; 声明。
C语言的头文件常用于声明函数、变量、宏和结构体等的定义,以便在多个源文件中共享和重用这些声明。
以下是C语言头文件的一般写法:
c
#ifndef HEADER_NAME_H
#define HEADER_NAME_H
// 在这里写下头文件的内容
#endif /* HEADER_NAME_H */
头文件的命名通常使用全大写字母,可以根据需要选择有意义的名称。
头文件中应该包含以下内容:
防止多重包含:使用条件编译指令#ifndef、#define 和#endif,以避免头文件被重复包含。
函数声明:声明函数的原型,例如int add(int a, int b);。
变量声明:声明变量的外部链接性,例如extern int globalVariable;。
宏定义:定义常量、宏函数和条件编译宏等,例如#define PI 3.14159。
结构体定义:定义结构体类型,例如struct Person { char name[20]; int age; };。
请注意以下几点:
头文件中通常只包含声明,而不包含具体的实现代码。
实现代码应该在对应的源文件中编写。
头文件应该包含所需的其他头文件,以确保所有依赖关系得到满足。
在编写头文件时,应使用预处理指令#ifdef 和#ifndef 来避免重复定义和冲突。
头文件应该尽量精简和模块化,只包含与该头文件相关的声明。
在头文件中避免定义全局变量,因为头文件可能会被多个源文件包含,这样会导致变量的重复定义。
正确编写和组织头文件可以提高代码的可读性、可维护性和重用性,推荐遵循良好的编码规范和项目约定。
c语⾔的头⽂件、宏、指针#include命令#include是⽂件包含命令,主要⽤来引⼊对应的头⽂件。
#include的处理过程很简单,就是将头⽂件的内容插⼊到该命令所在的位置,从⽽把头⽂件和当前源⽂件连接成⼀个源⽂件,这与复制粘贴的效果相同。
#include有两种使⽤⽅式:#include <stdio.h>#include "myHeader.h"使⽤尖括号< >和双引号" "的区别在于头⽂件的搜索路径不同:包含标准库的头⽂件建议⽤尖括号,包含⾃定义的头⽂件建议⽤双引号。
⼀个#include命令只能包含⼀个头⽂件,多个头⽂件需要多个#include命令。
⽂件包含允许嵌套,也就是说在⼀个被包含的⽂件中⼜可以包含另⼀个⽂件。
宏定义#define 宏名字符序列#表⽰这是⼀条预处理命令,所有的预处理命令都以#开头。
define是预处理命令。
宏名是标识符的⼀种,命名规则和标识符相同。
字符序列可以是常数、表达式等。
宏定义的⼏点说明宏定义是⽤宏名来表⽰⼀个字符串,在宏展开时⼜以该字符串取代宏名,这只是⼀种简单的替换。
字符串中可以含任何字符,可以是常数,也可以是表达式,预处理程序对它不作任何检查,如有错误,只能在编译已被宏展开后的源程序时发现。
宏定义不是说明或语句,在⾏末不必加分号,如加上分号则连分号也⼀起替换。
宏定义必须写在函数之外,其作⽤域为宏定义命令起到源程序结束。
如要终⽌其作⽤域可使⽤#undef命令。
#define A 123 #undefA A只在从定义到undef之间有效宏定义表⽰数据类型和⽤typedef定义数据说明符的区别。
宏定义只是简单的字符串代换,是在预处理完成的,⽽typedef是在编译时处理的,它不是作简单的代换,⽽是对类型说明符重新命名。
被命名的标识符具有类型定义说明的功能。
#define PIN1 int *typedef int *PIN2; //也可以写作typedef int (*PIN2);从形式上看这两者相似,但在实际使⽤中却不相同。
C语⾔中头⽂件和cpp⽂件解析回到cpp⽂件与头⽂件各写什么内容的话题上:理论上来说cpp⽂件与头⽂件⾥的内容,只要是C语⾔所⽀持的,⽆论写什么都可以的,⽐如你在头⽂件中写函数体实现,任何⼀个cpp⽂件包含此头⽂件就可以将这个函数编译成⽬标⽂件的⼀部分(编译是以cpp⽂件为单位的,如果不在任何cpp⽂件中包含此头⽂件的话,这段代码就形同虚设),你可以在cpp⽂件中进⾏函数声明、变量声明、结构体声明,这也不成问题那为何⼀定要分成头⽂件与cpp⽂件呢?⼜为何⼀般都在头件中进⾏函数、变量声明,宏声明,结构体声明呢?⽽在cpp⽂件中去进⾏变量定义,函数实现呢??原因如下: 1.如果在头⽂件中实现⼀个函数体,那么如果在多个cpp⽂件中引⽤它,⽽且⼜同时编译多个cpp⽂件,将其⽣成的⽬标⽂件连接成⼀个可执⾏⽂件,在每个引⽤此头⽂件的cpp⽂件所⽣成的⽬标⽂件中,都有⼀份这个函数的代码,如果这段函数⼜没有定义成局部函数,那么在连接时,就会发现多个相同的函数,就会报错,函数重复定义。
2.如果在头⽂件中定义全局变量,势必会对此全局变量赋初值,那么在多个引⽤此头⽂件的cpp⽂件中同样存在相同变量名的拷贝,关键是此变量被赋了初值,所以编译器就会将此变量放⼊DATA段,最终在连接阶段,会在DATA段中存在多个相同的变量,它⽆法将这些变量统⼀成⼀个变量,统⼀变量的意思也就是仅为此变量分配⼀个空间,⽽不是多份空间。
但是对于声明⼀个变量,这个变量在头⽂件没有赋初值,编译器就会将之放⼊BSS段,连接器会对BSS段的多个同名变量仅分配⼀个存储空间。
3.如果在cpp⽂件中声明宏、结构体、函数等,那么我要在另⼀个cpp⽂件中引⽤相应的宏、结构体、函数,就必须再做⼀次重复的⼯作(意思是说如果不去#include),如果我改了⼀个cpp⽂件中的⼀个声明,那么⼜忘了改其它cpp⽂件中的声明,这不就出了⼤问题了,程序的逻辑就变成了你不可想象的了,如果把这些公共的东东放在⼀个头⽂件中,想⽤它的cpp⽂件就只需要引⽤⼀个就OK了这样岂不⽅便,要改某个声明的时候,只需要动⼀下头⽂件就⾏了。
C++中头⽂件(.h)和源⽂件(.cpp)都应该写些什么头⽂件(.h):写类的声明(包括类⾥⾯的成员和⽅法的声明)、函数原型、#define常数等,但⼀般来说不写出具体的实现。
在写头⽂件时需要注意,在开头和结尾处必须按照如下样式加上预编译语句(如下):#ifndef CIRCLE_H#define CIRCLE_H//你的代码写在这⾥#endif这样做是为了防⽌重复编译,不这样做就有可能出错。
⾄于CIRCLE_H这个名字实际上是⽆所谓的,你叫什么都⾏,只要符合规范都⾏。
原则上来说,⾮常建议把它写成这种形式,因为⽐较容易和头⽂件的名字对应。
源⽂件(.cpp):源⽂件主要写实现头⽂件中已经声明的那些函数的具体代码。
需要注意的是,开头必须#include⼀下实现的头⽂件,以及要⽤到的头⽂件。
那么当你需要⽤到⾃⼰写的头⽂件中的类时,只需要#include进来就⾏了。
下⾯举个最简单的例⼦来描述⼀下,咱就求个圆⾯积。
第1步,建⽴⼀个空⼯程(以在VS2003环境下为例)。
第2步,在头⽂件的⽂件夹⾥新建⼀个名为Circle.h的头⽂件,它的内容如下:#ifndef CIRCLE_H#define CIRCLE_Hclass Circle{private:double r;//半径public:Circle();//构造函数Circle(double R);//构造函数double Area();//求⾯积函数};#endif注意到开头结尾的预编译语句。
在头⽂件⾥,并不写出函数的具体实现。
第3步,要给出Circle类的具体实现,因此,在源⽂件夹⾥新建⼀个Circle.cpp的⽂件,它的内容如下:#include "Circle.h"Circle::Circle(){this->r=5.0;}Circle::Circle(double R){this->r=R;}double Circle:: Area(){return 3.14*r*r;}需要注意的是:开头处包含了Circle.h,事实上,只要此cpp⽂件⽤到的⽂件,都要包含进来!这个⽂件的名字其实不⼀定要叫Circle.cpp,但⾮常建议cpp⽂件与头⽂件相对应。
C语⾔这些常⽤的标准库(头⽂件),你不得不知道...有很多⼯程师喜欢⾃⼰封装⼀些标准库已有的函数,其实⾃⼰封装的函数,并不⼀定⽐标准库好,有时候反⽽代码更冗余,且有bug。
下⾯⼩编就来分享⼀下C语⾔常见的⼀些标准库。
标准头⽂件包括:<asset.h><ctype.h><errno.h><float.h><limits.h><locale.h><math.h><stdio.h><signal.h><time.h><stddef.h><stdlib.h><string.h><stdarg.h><setjmp.h>⼀、标准定义(<stddef.h>)⽂件<stddef.h>⾥包含了标准库的⼀些常⽤定义,⽆论我们包含哪个标准头⽂件,<stddef.h>都会被⾃动包含进来。
这个⽂件⾥定义:●类型size_t(sizeof运算符的结果类型,是某个⽆符号整型);●类型ptrdiff_t(两个指针相减运算的结果类型,是某个有符号整型);●类型wchar_t(宽字符类型,是⼀个整型,其中⾜以存放本系统所⽀持的所有本地环境中的字符集的所有编码值。
这⾥还保证空字符的编码值为0);●符号常量NULL(空指针值);●宏offsetot (这是⼀个带参数的宏,第⼀个参数应是⼀个结构类型,第⼆个参数应是结构成员名。
offsetot(s,m)求出成员m在结构类型t的变量⾥的偏移量)。
注:其中有些定义也出现在其他头⽂件⾥(如NULL)。
⼆、错误信息(<errno.h>)<errno.h>定义了⼀个int类型的表达式errno,可以看作⼀个变量,其初始值为0,⼀些标准库函数执⾏中出错时将它设为⾮0值,但任何标准库函数都设置它为0。
在C语言中,当你在多个文件夹中组织代码,并且需要在一个文件中包含另一个文件夹中的头文件时,你可以使用不同的路径指定包含头文件的位置。
以下是一些常见的路径指定方式:
相对路径:使用相对路径来指定头文件的位置。
相对路径是相对于包含头文件的源文件的位置。
例如,如果你的源文件位于项目根目录的子文件夹中,并且头文件也在该子文件夹中,可以这样包含头文件:
#include "subfolder/header.h"
绝对路径:使用绝对路径来指定头文件的位置。
这种方式提供了头文件的完整路径,不依赖于源文件的位置。
例如:
#include "/home/user/project/include/header.h"
编译器选项:你还可以使用编译器选项来指定头文件的搜索路径。
例如,使用gcc编译器的-I 选项来添加头文件搜索路径:
gcc -I/path/to/include -o output_file source_file.c
这将告诉编译器在/path/to/include 文件夹中查找头文件。
环境变量:有些项目使用环境变量来指定头文件的搜索路径。
这种方式需要在编译器中设置相应的环境变量,以告诉编译器在哪里查找头文件。
Makefile:如果你使用Makefile来构建项目,你可以在Makefile中定义头文件搜索路径。
这样,你可以更灵活地管理头文件的包含路径。
要根据项目的特定需求和文件组织方式选择合适的路径指定方式。
通常情况下,相对路径和编译器选项是最常用的方式,因为它们相对简单并且易于维护。
C语言中的头文件与原文件简单的说其实要理解C文件与头文件(即.h)有什么不同之处,首先需要弄明白编译器的工作过程,一般说来编译器会做以下几个过程:1.预处理阶段2.词法与语法分析阶段3.编译阶段,首先编译成纯汇编语句,再将之汇编成跟CPU相关的二进制码,生成各个目标文件(.obj文件)4.连接阶段,将各个目标文件中的各段代码进行绝对地址定位,生成跟特定平台相关的可执行文件,当然,最后还可以用objcopy生成纯二进制码,也就是去掉了文件格式信息。
(生成.exe 文件)编译器在编译时是以C文件为单位进行的,也就是说如果你的项目中一个C文件都没有,那么你的项目将无法编译,连接器是以目标文件为单位,它将一个或多个目标文件进行函数与变量的重定位,生成最终的可执行文件,在PC上的程序开发,一般都有一个main函数,这是各个编译器的约定,当然,你如果自己写连接器脚本的话,可以不用main函数作为程序入口(main.c文件目标文件可执行文件)有了这些基础知识,再言归正传,为了生成一个最终的可执行文件,就需要一些目标文件,也就是需要C文件,而这些C文件中又需要一个main函数作为可执行程序的入口,那么我们就从一个C文件入手,假定这个C文件内容如下:#include#include"mytest.h"intmain(intargc,charargv){test=25;printf("test.................%d/n", test);}头文件内容如下:inttest;现在以这个例子来讲解编译器的工作:1.预处理阶段:编译器以C 文件作为一个单元,首先读这个C文件,发现第一句与第二句是包含一个头文件,就会在所有搜索路径中寻找这两个文件,找到之后,就会将相应头文件中再去处理宏,变量,函数声明,嵌套的头文件包含等,检测依赖关系,进行宏替换,看是否有重复定义与声明的情况发生,最后将那些文件中所有的东东全部扫描进这个当前的C文件中,形成一个中间“C文件”2.编译阶段,在上一步中相当于将那个头文件中的test变量扫描进了一个中间C文件,那么test变量就变成了这个文件中的一个全局变量,此时就将所有这个中间C文件的所有变量,函数分配空间,将各个函数编译成二进制码,按照特定目标文件格式生成目标文件,在这种格式的目标文件中进行各个全局变量,函数的符号描述,将这些二进制码按照一定的标准组织成一个目标文件3.连接阶段,将上一步成生的各个目标文件,根据一些参数,连接生成最终的可执行文件,主要的工作就是重定位各个目标文件的函数,变量等,相当于将个目标文件中的二进制码按一定的规范合到一个文件中再回到C文件与头文件各写什么内容的话题上:理论上来说C文件与头文件里的内容,只要是C语言所支持的,无论写什么都可以的,比如你在头文件中写函数体,只要在任何一个C文件包含此头文件就可以将这个函数编译成目标文件的一部分(编译是以C文件为单位的,如果不在任何C文件中包含此头文件的话,这段代码就形同虚设),你可以在C文件中进行函数声明,变量声明,结构体声明,这也不成问题那为何一定要分成头文件与C文件呢?又为何一般都在头件中进行函数,变量声明,宏声明,结构体声明呢?而在C 文件中去进行变量定义,函数实现呢??原因如下:1.如果在头文件中实现一个函数体,那么如果在多个C文件中引用它,而且又同时编译多个C文件,将其生成的目标文件连接成一个可执行文件,在每个引用此头文件的C文件所生成的目标文件中,都有一份这个函数的代码,如果这段函数又没有定义成局部函数,那么在连接时,就会发现多个相同的函数,就会报错2.如果在头文件中定义全局变量,并且将此全局变量赋初值,那么在多个引用此头文件的C文件中同样存在相同变量名的拷贝,关键是此变量被赋了初值,所以编译器就会将此变量放入DATA段,最终在连接阶段,会在DATA段中存在多个相同的变量,它无法将这些变量统一成一个变量,也就是仅为此变量分配一个空间,而不是多份空间,假定这个变量在头文件没有赋初值,编译器就会将之放入BSS段,连接器会对BSS段的多个同名变量仅分配一个存储空间3.如果在C文件中声明宏,结构体,函数等,那么我要在另一个C文件中引用相应的宏,结构体,就必须再做一次重复的工作,如果我改了一个C文件中的一个声明,那么又忘了改其它C文件中的声明,这不就出了大问题了,程序的逻辑就变成了你不可想象的了,如果把这些公共的东东放在一个头文件中,想用它的C文件就只需要引用一个就OK了这样岂不方便,要改某个声明的时候,只需要动一下头文件就行了4.在头文件中声明结构体,函数等,当你需要将你的代码封装成一个库,让别人来用你的代码,你又不想公布源码,那么人家如何利用你的库呢?也就是如何利用你的库中的各个函数呢??一种方法是公布源码,别人想怎么用就怎么用,另一种是提供头文件,别人从头文件中看你的函数原型,这样人家才知道如何调用你写的函数,就如同你调用printf函数一样,里面的参数是怎样的??你是怎么知道的??还不是看人家的头文件中的相关声明啊当然这些东东都成了C标准,就算不看人家的头文件,你一样可以知道怎么使用c语言中.c和.h文件的困惑?本质上没有任何区别。
在C语言中,头文件(header files)通常包含函数声明和宏定义,它们为源文件(source files)提供信息。
头文件以`.h`为后缀,通常采用简单的文本格式进行编写。
下面是一个示例,展示了C语言头文件的基本书写格式:```c/* 这是注释,用于说明头文件的目的和内容*/#ifndef HEADER_FILE_NAME_H // 如果未定义HEADER_FILE_NAME_H#define HEADER_FILE_NAME_H // 定义HEADER_FILE_NAME_H/* 在这里声明函数和定义宏*/// 函数声明示例void function_name(parameter_type parameter_name);// 宏定义示例#define MACRO_NAME value#endif /* HEADER_FILE_NAME_H */```这是一个典型的C语言头文件模板。
下面是对各个部分的解释:1. **注释**:头文件的顶部通常包含注释,用于解释头文件的目的和内容。
2. **防止头文件重复包含的保护**:这一部分确保头文件不会被重复包含。
`#ifndef`、`#define` 和`#endif` 是预处理器指令,它们在头文件被包含时确保只有一次定义。
`HEADER_FILE_NAME_H` 是你自己定义的名称,通常采用大写字母和下划线命名法。
3. **函数声明**:函数声明在头文件中以原型形式出现,告诉编译器函数的名称、返回类型以及参数。
例如,`void function_name(parameter_type parameter_name);` 是一个函数声明的示例。
4. **宏定义**:使用`#define` 预处理器指令可以定义宏。
例如,`#define MACRO_NAME value` 定义了一个名为`MACRO_NAME` 的宏,其值为`value`。
5. **结束保护**:最后再次使用`#endif` 来结束防止重复包含的保护。
文件包含与头文件的写法很多人对C语言中的“文件包含”都不陌生了,文件包含处理在程序开发中会给我们的模块化程序设计带来很大的好处,通过文件包含的方法把程序中的各个功能模块联系起来是模块化程序设计中的一种非常有利的手段。
文件包含处理是指在一个源文件中,通过文件包含命令将另一个源文件的内容全部包含在此文件中。
在源文件编译时,连同被包含进来的文件一同编译,生成目标目标文件。
很多人再初学时都会对这个很晕,怎么写文件件? 怎么包含才能避免重定义? 等等问题。
其实这个只要了解了文件包含的基本处理方法就可以对文件包含有一个很好的理解与应用了,下来我们一起来看一下:文件包含的处理方法:首先大家需要清楚:(1) 处理时间:文件包含也是以"#"开头来写的(#include ), 那么它就是写给预处理器来看了, 也就是说文件包含是会在编译预处理阶段进行处理的。
(2) 处理方法:在预处理阶段,系统自动对#include命令进行处理,具体做法是:降包含文件的内容复制到包含语句(#include )处,得到新的文件,然后再对这个新的文件进行编译。
抓住这两点,那么这个东东就没有什么难的了。
一般情况下文件包含分为两种:包含.h文件和包含.c文件1. 当然对于这两情况也都是按照上面说的方法来处理的。
呵呵,这个肯定是没得说的.2. 包含.c文件和编译多文件程序是不同的。
多文件程序: 是在源文件编译时把多个文件进行编译、连接在一起生成一个可执行文件。
包含.c文件:按照我们上边的说法则是把多个文件合并为一个文件进行编译。
接下来通过例子看一下:(1)包含.c文件:1://file1: main.c2: #include3: #include "fun.c"4:int main()5: {6:int a=5,b=19;7: c = a;8:sun(a,b);9:printf("c=%d\n",c);10:return 0;11: }12: //end of file11://file2: fun.c2:int c=0;3:void sun(int a, int b)4: {5: printf("a+b=%d\n",a+b);6: c=0;7: printf("c=%d\n",c);8: }9://end of file210:这个例子是采用包含.c文件的方法实现的。
在编译时,直接去编译main.c文件,预处理器会先把fun.c文件中的内容复制到main.c中来,然后再对新的main.c进行编译。
编译命令:gcc main.c -o main可以看到,这里并没有对fun.c进行编译,但还是生成了最终的main可执行程序。
也可以通过命令来观察一下预处理的结果:编译命令:gcc -E main.c -o main.cpp在main.cpp文件末尾可以看来下面一段代码:1://main.cpp文件中2: 931 # 2 "main.c" 23: 932 # 1 "fun.c" 14: 933 //注意这里是fun.c里边的内容5: 934 int c=0;6: 935 void sun(int a, int b)7: 936 {8: 937 printf("a+b=%d\n",a+b);9: 938 c=0;10: 939 printf("c=%d\n",c);11: 940 }12://这里是main函数13: 941 # 3 "main.c" 214: 942 int main()15: 943 {16: 944 int a=5,b=19;17: 945 c = a;18: 946 printf("c=%d\n",c);19: 947 sun(a,b);20: 948 printf("c=%d\n",c);21: 949 return 0;22: 950 }可见,其实就是将fun.c文件中的内容添加到了main函数之前,然后对新的文件进行编译,生成最终的可执行程序。
(2)编译多文件程序:同样是上边的例子,把main.c中“ #include "fun.c" ”注释掉,加上一句:“extern int c;”因为 c 变量在另外一个文件(fun.c)中定义。
1://file1: main.c2: #include3://#include "fun.c" //注释掉4:extern int c; //添加这一句5:int main()6: {7:int a=5,b=19;8: c = a;9: sun(a,b);10: printf("c=%d\n",c);11:return 0;12: }13://end of file114:15:16://file2: fun.c17:int c=0;18:void sun(int a, int b)19: {20: printf("a+b=%d\n",a+b);21: c=0;22: printf("c=%d\n",c);23: }24: //end of file2这次如果还是按照上面的方法只编译main.c的话就会出错,因为变量c和函数sun并没有在main.c中定义,所以编译时需要将fun.c一起编译:编译命令:gcc -c main.c -o main.o #编译main.cgcc -c fun.c -o fun.o #编译fun.cgcc main.o fun.o -o main #用main.o fun.o生成main到这里大家应该已经理解包含.c文件和多文件程序的本质区别了~~~好了,大家不防想想这两种方法的优缺点,这里就只写不足之处了:1. 包含.c文件的方法: 容易产生"重定义",大家想想如果一个工程中有多个文件都同时包含了某一个件,那么这个被包含文件的内容就会被复制到多个文件中去,也就相当于每个包含该文件的文件中都定义被包含文件中的变量和函数,这样在链接时就会产生"重定义"错误。
2. 多文件分开编译的方法: 这个比较好,不容易出现"重定义"之类的问题,这也是我们最常用的一种方法,但是并不是像上面这个例子中这样直接去用,而是使用"头文件"将各个.c文件联系起来。
上边这个例子大家会发现,在main.c中需要加上“extern int c;”这样一句声明,如果包含的文件较多?如果全局变量较多?...这个我们可以省掉吗?回答是肯定的!方法就是给它写上一个头文件。
接下来看一下使用头文件的来实现这个例子的方法:1://file1: main.c2: #include3: #include "fun.h"//fun.c修改为fun.h4://extern int c; //这行也不要了5:int main()6: {7:int a=5,b=19;8: c = a;9:sun(a,b);10:printf("c=%d\n",c);11:return 0;12: }13: //end of file11:2://file2: fun.c3: #include "fun.h"4:int c=0; //变量c的定义5:void sun(int a, int b) //函数sun()的定义6: {7:printf("a+b=%d\n",a+b);8:c=0;9:printf("c=%d\n",c);10: }11://end of file21://file3: fun.h2:extern int c; //把c声明为外部可用的3:void sun(int a, int b); //sun()函数的声明4://end of file3这样再看一下,在要用到fun.c中定义的函数或变量的文件中只要包含fun.h文件就可以了,是不是这样???呵呵,当然是了。
预处理时会把fun.h中的内容复制到包含它的文件中去,而复制的这些内容只是声名,不是定义,所以它被复制再多份也不会出现"重定义"的错误。
呵呵,对,就是这样,这就是头文件给我们再来的好处。
前面说了头文件的方法也是模块化程序设计中的一种非常有利的手段。
把同一类功能写到一个.c文件中,这样可以把他们划为一个模块,另外再对应的写上一个.h文件做它的声明。
这样以后再使用这个模块时只需要把这两个文件添加进工程,同时在要使用模块内函数或变量的文件中包含.h文件就可以了。
举个很实际的例子,在单片机、ARM或其他嵌入式开发中,每一个平台可能本身都有多种不同的硬件模块,使用时需要去写相应的驱动程序,这样就可以把各个硬件模块的驱动程序作为一个模块(比如lcd 驱动对对应lcd.c和lcd.h,IIC驱动对应I2C.c和I2C.h等),当具体使用到某个模块时,只需要在将对应的.c 和.h文件添加进工程,并在文件中包含对就的.h文件即可。
所以关于头文件的写法个人总结以下几点:(1) 对应的.c文件中写变量、函数的定义(2) 对应的.h文件中写变量、函数的声明(3) 如果有数据类型的定义和宏定义,请写的头文件(.h)中(4) 头文件中一定加上#ifndef...#define....#endif之类的防止重包含的语句(5) 模块的.c文件中别忘包含自己的.h文件呵呵,OK,就这些了,写的有点乱哦,希望对大家有帮助。