曲径通幽论坛

标题: 头文件的作用及其管理 [打印本页]

作者: beyes    时间: 2013-10-3 11:29
标题: 头文件的作用及其管理
一个大型的软件项目,组织单元通常是“头文件”+相应的”源代码文件“。


头文件包含了结构声明,以及使用这些结构的函数原型。源代码文件则是这些函数原型的实现代码。

不要将函数的定义或变量的声明放到头文件中,尽管这对于简单的情况是可以的,但通常会带来麻烦。比如在一个头文件中包含了一个函数的定义,然后在其它两个文件(属于同一个程序)中包含了该头文件,则同一个程序中就包含了同一个函数的两个定义 --- 除非该函数是内联函数 --- 否则这就会出错。

头文件通常包含的内容有:







将结构声明放在头文件中是没有问题的,因为它们仅是声明而已,并不会创建变量,只有在源代码文件中声明结构变量时,编译器才会去创建该结构变量。同样,模板声明也不是要被编译的代码,它只是指示编译器如何生成与源代码中的函数调用相匹配的函数定义。被声明为 const 的数据和内敛函数有特殊的链接属性,也可以放在头文件中而不会引起什么问题。


如果头文件使用尖括号括起来的,如 <iostream> ,那么编译器就会在存储标准头文件的目录中查找;如果是用双引号括起来的,那么就在当前工作目录或源代码目录中查找,还可能是其它目录,这取决于编译器。


#include 是用来包含和管理头文件的,而不是源代码文件,如果 #include 了代码文件,那么将导致多重声明的错误。


头文件的管理


有一个重要的规则是,在同一个文件中只能将同一个头文件包含一次。

但是很可能在不知情的情况下将头文件包含多次。比如,可能使用包含了另外一个头文件的头文件。对此,有一种标准的 C/C++ 技术可以避免多次包含同一头文件。它是基于预处理器编译指令 #ifndef (if not defined)。下面代码片段表示仅当以前没有使用预处理器编译指令 #define 定义名称 JUSTONE_H_ 时,才处理 #ifndefendif 之间的语句:
  1. #ifndef JUSTONE_H_
  2. ...
  3. #endif
复制代码
通常,使用 #define 语句来创建符号常量,如 #define SPEED 512 。但它可以直接用于一个名称,那么就足以完成该名称的定义,比如: #define JUSTONE_H_ ,这样我们就有:
  1. #ifndef JUSTONE_H_
  2. #define JUSTONE_H_
  3. // 这里放置头文件的内容
  4. #endif
复制代码
那么,在编译器首次遇到该文件时,名称 JUSTONE_H_ 没有定义。这样,编译器就会检查 #ifndef#endif 之间的内容,并读取定义 JUSTONE_H_ 这一行。如果在同一个文件中遇到其他包含该头文件的代码,编译器就会知道 JUSTONE_H_ 已经被定义了,从而跳转到 #endif 后面一行上,即略过 #ifndef#endif 之间的内容。使用这种方法,可以使编译器忽略除了第一次包含之外的所有内容。大多数标准的 C 和 C++ 头文件都使用这种防护 (guarding) 方案。否则,可能在一个文件中定义同一个结构两次或多次,这就会导致编译错误。

对于 Microsoft 的 Visual Studio C++ ,它提供了一个更方便的预处理指令 pragma once ,它实际上就是上述的一种缩写,细节可参考:http://www.groad.net/bbs/thread-7944-1-1.html





欢迎光临 曲径通幽论坛 (http://www.groad.net/bbs/) Powered by Discuz! X3.2