您的位置:首页 > 编程语言 > C语言/C++

C语言头文件的看法

2013-11-26 16:58 127 查看
1 术语

1.1 定义与声明

定义:建立存储空间。声明:不需要建立存储空间,仅仅是为了扩展该变量的作用范围而作的“声明”。

定义只能有一次,但声明可以很多。如int Num为定义,而extern Num或extern int Num则为声明。

1.2 变量的分类

l 作用域来分:局部变量与全局变量

l 生存期来分:静态存储方式(分配固定的存储空间)与动态存储方式(根据需要进行动态的分配),具体有4种:自动的auto,静态的static,寄存器的register,外部的extern。

n auto变量如果没有特别声明是static,则默认的变量都是auto

n static 用static声明局部变量:在函数调用结束后其值不消失,而保留原值,即其占用的存储单元不释放。(在编译时赋初值,即只赋初值一次,在程序运行时它已有初值)(虽然静态局部变量在函数调用结束后仍然存在,但其他函数是不能引用它的)

n 用static声明外部变量 变量只限于本文件引用,而不能被其他文件引用

1.3 内部函数与外部函数

内部函数又称静态函数:只能被本文件中其他函数所调用。定义内部函数时,在前面添加static。

外部函数:定义时添加关键字extern,在定义时省略extern,则隐含为外部函数。在需要调用此函数的文件中,用extern对函数作声明,表示该函数是在其他文件中定义的外部函数。

1.4 作用域

2 编译器的工作过程

  简单的说其实要理解C文件与头文件(即.h)有什么不同之处,首先需要弄明白编译器的工作过程,一般说来编译器会做以下几个过程:

  1.预处理阶段

  2.词法与语法分析阶段

  3.编译阶段,首先编译成纯汇编语句,再将之汇编成跟CPU相关的二进制码,生成各个目标文件 (.obj文件)

  4.连接阶段,将各个目标文件中的各段代码进行绝对地址定位,生成跟特定平台相关的可执行文件,当然,最后还可以用objcopy生成纯二进制码,也就是去掉了文件格式信息。(生成.exe文件)

编译器在编译时是以C文件为单位进行的,也就是说如果你的项目中一个C文件都没有,那么你的项目将无法编译,连接器是以目标文件为单位,它将一个或多个目标文件进行函数与变量的重定位,生成最终的可执行文件,在PC上的程序开发,一般都有一个main函数,这是各个编译器的约定,当然,你如果自己写连接器脚本的话,可以不用main函数作为程序入口!

(main .c文件 目标文件 可执行文件)

2.1 头文件如何来关联源文件?

  这个问题实际上是说,已知头文件"a.h"声明了一系列函数(仅有函数原型,没有函数实现),"b.cpp"中实现了这些函数,那么如果我想在"c.cpp"中使用"a.h"中声明的这些在"b.cpp"中实现的函数,通常都是在"c.cpp"中使用#include
"a.h",那么c.cpp是怎样找到b.cpp中的实现呢?

  其实.cpp和.h文件名称没有任何直接关系,很多编译器都可以接受其他扩展名。

  谭浩强老师的《C程序设计》一书中提到,编译器预处理时,要对#include命令进行"文件包含处理":将headfile.h的全部内容复制到#include
"headfile.h"处。这也正说明了,为什么很多编译器并不care到底这个文件的后缀名是什么----因为#include预处理就是完成了一个"复制并插入代码"的工作。

  程序编译的时候,并不会去找b.cpp文件中的函数实现,只有在link的时候才进行这个工作。我们在b.cpp或c.cpp中用#include "a.h"实际上是引入相关声明,使得编译可以通过,程序并不关心实现是在哪里,是怎么实现的。源文件编译后成生了目标文件(.o或.obj文件),目标文件中,这些函数和变量就视作一个个符号。在link的时候,需要在makefile里面说明需要连接哪个.o或.obj文件(在这里是b.cpp生成的.o或.obj文件),此时,连接器会去这个.o或.obj文件中找在b.cpp中实现的函数,再把他们build到makefile中指定的那个可以执行文件中。

3 头文件的作用

l 头文件可以定义所用的函数列表,方便查阅你可以调用的函数;

l 头文件可以定义很多宏定义,就是一些全局静态变量的定义,在这样的情况下,只要修改头文件的内容,程序就可以做相应的修改,不用亲自跑到繁琐的代码内去搜索。

l 头文件只是声明,不占内存空间,要知道其执行过程,要看你头文件所申明的函数是在哪个.c文件里定义的,才知道。

l 头文件并不是C自带的,可以不用。

l 调用了头文件,就等于赋予了调用某些函数的权限,如果你要算一个数的N次方,就要调用Pow()函数,而这个函数是定义在math.c里面的,要用这个函数,就必需调用math.h这个头文件。

4 头文件的一般规则

a.宏定义(预处理#define);

b.结构、联合和枚举声明;

c.typedef声明;(typedef long doubleREAL;)

d.外部函数声明;

e.全局变量声明;

5 实际应用

l 定义宏常量或宏公式的时候,一定要加圆括号

l 头文件只声明不定义

l C语言中一个人为的规范:在.h文件中声明的函数,如果在其对应的.c文件中有定义,那么我们在声明这个函数时,不使用extern修饰符, 如果反之,则必须显示使用extern修饰符(即在不同的.h文件中,声明该函数,要添加extern).
可以用extern Num,而不是非要extern char Num。

l 不能把实际的代码(如函数体)或全局变量定义(即定义和初始化实例)放入头文件中。
l 不要试图用#include把你的源文件“链接”成一个整体。#include是用来引入头文件而不是.c文件的。
l 如果定义或声明为一个源文件私有则最好留在该文件中。(作用域限于单文件的私有函数和变量应该声明为static。)

l 当声明或定义需要在多个文件中共享时,把他们放入一个头文件中尤其重要。不要在两个或多个源文件的顶部重复声明或定义宏。应该把它们放入一个头文件中,然后在需要的时候用#include包含进来。这样做的原因并不仅仅是减少打字输入——这样可以保证在声明或定义变化的时候,只需要修改一处即可将结果一致地传播到各个源文件。(特别是,永远不要把外部函数原型放到.c文件中。参见2.)
l 当希望在多个源文件中共享变量或函数时,需要确保定义和声明的一致性。最好的安排是在某个相关的.c文件中定义,然后再头.h文件中进行外部声明,在需要使用的时候,只要包含对应的头文件即可。定义变量的.c文件也应该包含该头文件,以便编译器检查定义的和声明的一致性。
l 定义一个Globel_Var.C文件来放全局变量,然后在与之相对应的Globel_Var.H文件中来声明全局变量
l 防止被重复包含。
使用下面的宏防止一个头文件被重复包含。
#ifndef MY_INCLUDE_H
#define MY_INCLUDE_H
<头文件内容>
#endif

l 说明性头文件

还有一种头文件,说明性头文件,这种头文件不需要有一个对应的代码文件,在这种文件里大多包含了大量的宏定义,没有暴露的数据变量和函数。这些文件给出以下建议:
1,包含一些需要的概念性的东西.
2,命名方式,定义的功能.h
3,不包含任何其他的头文件.
4,不定义任何类型.
5,不包含任何数据和函数声明.
6 引用

/article/8605492.html

C语言头文件的使用

/article/9081392.html

C语言的变量作用域及头文件

/article/6025203.html

C语言头文件的作用
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: