C程序中头文件相互包含精华(转载)

C程序中头文件相互包含精华(网摘小结) 收藏(转自:http://blog.csdn.net/lingyun3429/archive/2010/04/27/5535191.aspx
.h中一般放的是同名.c文件中定义的变量、数组、函数的声明,需要让.c外部使用的声明。

1)h文件作用

1 方便开发:包含一些文件需要的共同的常量,结构,类型定义,函数,变量申明;

2 提供接口:对一个软件包来说可以提供一个给外界的接口(例如: stdio.h)。

2)h文件里应该有什么

常量,结构,类型定义,函数,变量申明。

3)h文件不应该有什么

变量定义, 函数定义。

4)extern问题

对于变量需要extern;

对于函数不需要因为函数的缺省状态是extern的.如果一个函数要改变为只在文件内可见,加static。

5)include包含问题

虽然申明和类型定义可以重复,不过推荐使用条件编译。

#ifndef _FILENAME_H,

#define _FILENAME_H

……

#endif

6)应该在那儿包含h文件

在需要的地方.比如某个提供接口的h文件仅仅被1.c文件需要,那么就在1.c文件里包含。

编写的程序一般会有.H文件和相对应的.C文件,.H文件是声明所用,.C文件是其函数实现部分。在调用时只要包含.H文件即可,我们没有听说过#include "delay.c"这类的程序,同时也不提倡使用这个形式。

在delay.h文件中:                //对调用的函数声明

#ifndef __DELAY_H__

#define __DELAY_H__

extern void Delayms(unsigned int n);

#endif

在delay.c文件中:                 //函数实现部分

#include <delay.h>

//for crystal 11.0592M

void Delayms(unsigned int n)

{

unsigned int i,j;

for(j=n;j>0;j--)

for(i=112;i>0;i--);

}

在主程序main.c中

#include <delay.h>                //在主程序包含.h文件,不能包含.c文件

通常一个C程序工程按功能可以分成多个模块, 一个模块通常由两个文档组成一个头文件 *.h, 对模块中的数据结构和函数原型进行描述;另一个为C文件*.C , 对数据实例或对象进行定义,以及函数算法的具体实现,如I2C.C, SPI.C, DAC.C, DISPLAY.C 等,为了文件的调用,我们要为每个模块定义一个头文件,以I2C.C 来说,定义I2C.H。

#ifndef GRAPHICS_H

#define GRAPHICS_H

#include   <math.h >

#include   “myheader.h”

void   Function1(…);

class   Box

{

};

#endif

******************************************************************************************************************************************************************************************************************

模块化的程序是黑盒,只向外提供接口(全局变量、外部函数),而不需要让调用者了解其中过程。尽可能地少定义接口有利于保持模块的独立性(不需要让使用者知道的内部函数与静态全局变量不需要在H文件中给出以避免使用者疑惑)在需要调用此模块的文件中写入include语句。一个好的工程,H文件的组织是很清晰的,只看H文件就能够写主程序调用相应的C模块。

头文件的格式如下(I2C.H为例):

********************************************************************

#ifndef   I2C_H

#define   I2C_H

..........

bit  SetSDA ( bit  Up_Down );

bit   SetSCL ( bit  Up_Down);

#endif

**********************************************************************

I2C.C格式如下:

**********************************************************************

#include  < stdio.h >

#include  "I2C.h"

void SendByte ( uchar c );

bit  SetSDA ( bit  Up_Down )     { .......... };

bit   SetSCL ( bit  Up_Down)     { .......... };

**********************************************************************

另外一种写法:

=============================

#ifndef   I2C_H

#define   I2C_H

..........

exten  bit  SetSDA ( bit  Up_Down );

exten  bit   SetSCL ( bit  Up_Down);

#endif

=================================================

I2C.C格式如下:

=================================================

#include  < stdio.h >

void SendByte ( uchar c );

bit  SetSDA ( bit  Up_Down )     { .......... };

bit  SetSCL ( bit  Up_Down)      { .......... };

=================================================

举个例子,顺便分析一下ifndef/define/endif:

假设你的工程里面有4个文件,分别是a.cpp, b.h, c.h, d.h。

a.cpp的头部是:

#include   "b.h"

#include   "c.h"

b.h和c.h的头部都是:

#include   "d.h"

而d.h里面有class D的定义。

这样一来, 编译器编译a.cpp的时候,先根据#include "b.h"去编译b.h这个问题,再根据b.h里面的#include "d.h",去编译d.h的这个文件,这样就把d.h里面的class D编译了;

然后再根据a.cpp的第二句#include "c.h",去编译c.h,最终还是会找到的d.h里面的class D,但是class D之前已经编译过了,所以就会报重定义错误。

加上ifndef/define/endif,就可以防止这种重定义错误。在预编译的过程中,执行到include "C.h"时会因为在上一句的时候已经定义了class D这个宏,所以此时的ifndef条件不满足,起到了防止重复引用头文件的效果。

#undef只是撤消掉掉原来定义的宏,但是不会取消掉你已经用这个宏定义的变量

#define   X   extern

x   int   a;

#undef   X

你仍然可以使用这个a,但不能用X了,当然你再定义X成什么就随便了

你也可以再定义成

#define   X   extern

x   int   a;

#undef    X

#define   X   int

X   b;

#undef    X

******************************************************************************************************************************************************************************************************************

模块划分的"划"是规划的意思,意指怎样合理的将一个很大的软件划分为一系列功能独立的部分合作完成系统的需求。C语言作为一种结构化的程序设计语言,在模块的划分上主要依据功能(依功能进行划分在面向对象设计中成为一个错误,牛顿定律遇到了相对论),C语言模块化程序设计需理解如下概念:

(1) 模块即是一个.c文件和一个.h文件的结合,头文件(.h)中是对于该模块接口的声明;

(2) 某模块提供给其它模块调用的外部函数及数据需在.h中文件中冠以extern关键字声明;

(3) 模块内的函数和全局变量需在.c文件开头冠以static关键字声明;

(4) 永远不要在.h文件中定义变量!定义变量和声明变量的区别在于定义会产生内存分配的操作,是汇编阶段的概念;而声明则只是告诉包含该声明的模块在连接阶段从其它模块寻找外部函数和变量。如:

int a = 5;

#include "module1.h"

#include "module1.h"

#include "module1.h"

  以上程序的结果是在模块1、2、3中都定义了整型变量a,a在不同的模块中对应不同的地址单元,这个世界上从来不需要这样的程序。正确的做法是:

extern int a;

#include "module1.h" int a = 5;

#include "module1.h"

#include "module1.h"

这样如果模块1、2、3操作a的话,对应的是同一片内存单元。

******************************************************************************************************************************************************************************************************************

程序设计也是如此,如果概念很清晰,那基本上没什么难题(会难在数学上,比如算法的选择、时间空间与效率的取舍、稳定与资源的平衡上)。但是,要掌握清晰的概念也没那么容易。比如下面这个例子,看看你有没有很清晰透彻的认识。

//a.h

void foo();

//a.c

#include "a.h"  //我的问题出来了:这句话是要,还是不要?

void foo()

{

return;

}

//main.c

#include "a.h"

int main(int argc, char *argv[])

{

foo();

 return 0;

}

针对上面的代码,请回答三个问题:

a.c 中的 #include "a.h" 这句话是不是多余的?
为什么经常见 xx.c 里面 include 对应的 xx.h?
如果 a.c 中不写,那么编译器是不是会自动把 .h 文件里面的东西跟同名的 .c 文件绑定在一起?
(请针对上面3道题仔细考虑10分钟,莫要着急看下面的解释。:) 考虑的越多,下面理解的就越深。)

  好了,时间到!请忘掉上面的3道题,以及对这三道题引发出的你的想法,然后再听我慢慢道来。正确的概念是:从C编译器角度看,.h和.c皆是浮云,就是改名为.txt、.doc也没有大的分别。换句话说,就是.h和.c没啥必然联系。.h中一般放的是同名.c文件中定义的变量、数组、函数的声明,需要让.c外部使用的声明。这个声明有啥用?只是让需要用这些声明的地方方便引用。因为 #include "xx.h" 这个宏其实际意思就是把当前这一行删掉,把 xx.h 中的内容原封不动的插入在当前行的位置。由于想写这些函数声明的地方非常多(每一个调用 xx.c 中函数的地方,都要在使用前声明一下子),所以用 #include "xx.h" 这个宏就简化了许多行代码——让预处理器自己替换好了。也就是说,xx.h 其实只是让需要写 xx.c 中函数声明的地方调用(可以少写几行字),至于 include 这个 .h 文件是谁,是 .h 还是 .c,还是与这个 .h 同名的 .c,都没有任何必然关系。
  这样你可能会说:啊?那我平时只想调用 xx.c 中的某个函数,却 include了 xx.h 文件,岂不是宏替换后出现了很多无用的声明?没错,确实引入了很多垃圾,但是它却省了你不少笔墨,并且整个版面也看起来清爽的多。鱼与熊掌不可得兼,就是这个道理。反正多些声明(.h一般只用来放声明,而放不定义,参见拙著“过马路,左右看”)也无害处,又不会影响编译,何乐而不为呢?
翻回头再看上面的3个问题,很好解答了吧?

答:不一定。这个例子中显然是多余的。但是如果.c中的函数也需要调用同个.c中的其它函数,那么这个.c往往会include同名的.h,这样就不需要为声明和调用顺序而发愁了(C语言要求使用之前必须声明,而include同名.h一般会放在.c的开头)。有很多工程甚至把这种写法约定为代码规范,以规范出清晰的代码来。
答:1中已经回答过了。
答:不会。问这个问题的人绝对是概念不清,要不就是想混水摸鱼。非常讨厌的是中国的很多考试出的都是这种烂题,生怕别人有个清楚的概念了,绝对要把考生搞晕。

时间: 2024-10-23 22:54:54

C程序中头文件相互包含精华(转载)的相关文章

C/C++ 中头文件相互包含引发的问题

今天下午遇到一个头文件相互包含而导致的编译问题,花了我不少时间去调试没找到问题,最后晚上跟师兄讨论不少时间,突然有所顿悟! 问题重现 我把问题脱离于项目简单描述一下:我写了一个函数 bool func(ClassA* CA) 需要加到项目中,我就把这个函数的声明放到 head1.h 中,函数参数类型 ClassA 定义在另一个头文件 head2.h 中,因此我需要在 head1.h 中包含 head2.h:而 head2.h 中之前又包含了 head1.h,这样就构成了一种头文件相互包含的场景.

C++ 头文件相互包含的问题

今天在看C++ Primer第7章,一个习题是要写两个类,一个是Screen类,一个Window_mgr类,其中,Window_mgr类包含有一个vector<Screen>类型的成员 和一个clear函数,用于操作Screen类,所以需要把clear函数声明为Screen类的友元函数,这样就需要在定义Screen类的头文件中包含Window_mgr类的头文件,同理也需要在Window_mgr类中包含Screen类的头文件,如下: Screen.h #ifndef SCREEN_H #defi

头文件相互包含出错问题解决

今天写程序遇到了一个问题,花了好几个小时各种找资料都没有解决,终于皇天不负有心人还是让我给把它kill 掉了.什么问题呢?那就是头文件相互包含出错(当然之前我并不知道是这个原因),先来看代码: Test1.h #include "cocos2d.h" #include "Test2.h" class Test1 : public Layer {     ----     Test2 *test2; }; Test2.h #include "cocos2d.

C++中头文件一般包含哪些东西?

头文件和源文件 由于头文件是为了重用,所以在一个复杂的程序中,头文件可能会被间接地重复包含.如果头文件里面都是函数声明,那问题还不大.如果头文件里面有函数定义(如程序11.2),那么就会出现函数被重复定义的错误,程序将无法运行.我们可以采用函数声明和定义分离的方式:把所有的声明都放在shape.h中,把所有的定义放在shape.cpp中.注意必须在shape.cpp中包含shape.h,否则在编译连接时会发生错误.我们在使用时仍然包含shape.h,但由于函数的定义并不在该头文件中,所以就不会被

C/C++ 中头文件相互包括引发的问题

今天下午遇到一个头文件相互包括而导致的编译问题,花了我不少时间去调试没找到问题.最后晚上跟师兄讨论不少时间,突然有所顿悟! 问题重现 我把问题脱离于项目简单描写叙述一下:我写了一个函数 bool func(ClassA* CA) 须要加到项目中,我就把这个函数的声明放到 head1.h 中,函数參数类型 ClassA 定义在还有一个头文件 head2.h 中,因此我须要在 head1.h 中包括 head2.h:而 head2.h 中之前又包括了 head1.h.这样就构成了一种头文件相互包括的

没有躲过的坑--头文件相互包含(Compiler error C2653: not a class or namespace name)

最近被自己坑儿了一把,改别人的代码,最后编译器这样报错的: error C2653: not a class or namespace name 简单描述一下: 有一个类A,声明和实现分别位于 a.h和a.cc中 有一个类B,声明和实现分别位于 b.h和b.cc中 类A的某个成员函数需要B类类型作为参数 类B的某个成员函数需要A类类型作为参数 a.h文件如下: #ifndef A_H_ #define A_H_ #include "b.h" class A { public: enum

c中头文件在cpp文件中引用和.h文件引用的思考

我们在编写程序中头文件是经常使用的.但是头文件是应该包含在.H文件中还是在.cpp文件中.在这个当中有什么样去区别呢.  假如说我们编写了一个a.cpp  .我们将a.cpp文件的变量和函数申明在a.h中.在a.h文件有使用了b.中定义的类型type1数据m_type,同样b.cpp的头文件一些变量也声明在b.h中.此时我们当然可以在a.cpp中包含b.h 也可以在a.h中.这样都是可行的,因为我们编译的时候会会将b.h包含进来.而.h文件是不参与编译的.然后我们继续深入.假如我们将b.h文件定

C++中头文件与源文件的作用详解

一.C++ 编译模式 通常,在一个 C++ 程序中,只包含两类文件―― .cpp 文件和 .h 文件.其中,.cpp 文件被称作 C++ 源文件,里面放的都是 C++ 的源代码:而 .h 文件则被称作 C++ 头文件,里面放的也是 C++ 的源代码. C++ 语言支持"分别编译"(separatecompilation).也就是说,一个程序所有的内容,可以分成不同的部分分别放在不同的 .cpp 文件里..cpp 文件里的东西都是相对独立的,在编译(compile)时不需要与其他文件互通

Makefile中头文件在依赖关系中作用

摘于:http://bbs.csdn.net/topics/120024677 (1)在makefile的依赖关系中用不用体现.h头文件?(2)如果在依赖关系中要体现.h头文件,应该体现到什么层次?==============================(1)在makefile的依赖关系中用不用体现.h头文件?============================== 下面是我的一些认识: 头文件中定义的是接口(函数接口,文件外全局变量和宏定义),它的作用是向调用文件封装函数的实现过程.在