C/C++之头文件的作用

2015/06/17 C和C++基础

我们常常在编写代码的时候用到头文件,因为一个大的工程不可能只有一个源文件,肯定会有多个源文件,它们之间的联系可以通过报含头文件来解决。

在源文件xxx.cpp中添加语句#include “xxx.h”,作用就是把xxx.h文件中所有内容代码段都复制到xxx.cpp文件中

理论概述

xxx.h文件中一般放的是xxx.cpp文件中定义的变量、数组、函数的声明

1)xxx.h文件作用: 

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

2.使函数的作用域从函数声明的位置开始,而不是函数定义的位置;

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

2)xxx.h文件里应该有什么:常量,结构,类型定义,函数,变量申明

3)xxx.h文件不应该有什么:变量定义, 函数定义

4)include包含问题:虽然申明和类型定义可以重复,不过推荐使用条件编译。

#ifndef _FILENAME_H
#define _FILENAME_H
.
.
.
#endif
变量声明和定义的区别

变量的声明有两种情况:

1、一种是需要建立存储空间的。例如:int a 在声明的时候就已经建立了存储空间。

2、另一种是不需要建立存储空间的。 例如:extern int a 其中变量a是在别的文件中定义的。

前者是定义性声明(defining declaration)或者称为定义(definition),而后者是引用性声明(referncing declaration),从广义的角度来讲声明中包含着定义,即定义是声明的一个特例,所以并非所有的声明都是定义,例如:int a 它既是声明,同时又是定义。然而对于 extern a 来讲它只是声明不是定义。一般的情况下我们常常这样叙述,把建立空间的声明称之为“定义”,而把不需要建立存储空间的声明称之为“声明”。很明显我们在这里指的声明是范围比较窄的,即狭义上的声明,也就是说非定义性质的声明,例如:在主函数中:

int main() {
//这是个声明而不是定义,声明A是一个已经定义了的外部变量
//注意:声明外部变量时可以把变量类型去掉如:extern A;
extern int A;
dosth(); //执行函数
}
int A;    //是定义,定义了A为整型的外部变量

外部变量的“定义”与外部变量的“声明”是不相同的,外部变量的定义只能有一次,它的位置是在所有函数之外,而同一个文件中的外部变量声明可以是多次的,它可以在函数之内(哪个函数要用就在那个函数中声明)也可以在函数之外(在外部变量的定义点之前)。系统会根据外部变量的定义(而不是根据外部变量的声明)分配存储空间的。对于外部变量来讲,初始化只能是在“定义”中进行,而不是在“声明”中。所谓的“声明”,其作用,是声明该变量是一个已在后面定义过的外部变量,仅仅是为了“提前”引用该变量而作的“声明”而已。extern 只作声明,不作任何定义。

我们声明的最终目的是为了提前使用,即在定义之前使用,如果不需要提前使用就没有单独声明的必要,变量是如此,函数也是如此,所以声明不会分配存储空间,只有定义时才会分配存储空间。

用static来声明一个变量的作用有二:

(1)对于局部变量用static声明,则是为该变量分配的空间在整个程序的执行期内都始终存在。

(2)外部变量用static来声明,则该变量的作用只限于本文件模块。

例子1

//test1.cpp
#include <stdio.h>

int main(){
	printf("Hello World\n");
	return 0;
}

test1.cpp中并没有.h文件,编译可以顺利通过。把程序做下改动:

//test2.cpp
#include <stdio.h>

void prtstr(){
	printf("Hello World!\n");
}

int main(){
	prtstr();
	return 0;
}

test2.c中还是没有.h文件,编译仍可以顺利通过。再把程序改动下:

//test3.cpp
#include <stdio.h>

int main(){
	prtstr();
	return 0;
}

void prtstr(){
	printf("Hello World!\n");
}

test3.c中仍然没有.h文件,编译失败了。

我们在这里只讲述与.h文件相关的顶层作用域,顶层作用域就是从声明点延伸到源程序文本结束,就prtstr()这个函数来说,他没有单独的声明,只有定义,那么就从他定义的行开始,到文件结束,也就是说,在test2.c的main()函数的引用点上,已经是他的作用域。test3.c的main()函数的引用点上,还不是他的作用域,所以会编译出错。这种情况怎么办呢? 有两种方法,一个就是让我们回到test2.c,顺序对我们来说没什么,谁先谁后不一样呢,只要能编译通过,程序能运行,就让main()文件总是放到最后吧。那就让我们来看另一个例程,让我们看看这个方法是不是在任何时候都会起作用。

//test4.cpp
#include <stdio.h>

void play2(){
	play1();
}

void play1(){
	play2();
}

int main(){
	play1();
	return 0;
}

这就是经常用到的一种算法,函数嵌套。play1 和play2 这两个函数哪个放到前面呢?这时就需要我们来使用第二种方法,使用声明。

//test5.cpp
#include <stdio.h>

void play1();
void play2();

void play2(){
	play1();
}

void play1(){
	play2();
}

int main(){
	play1();
	return 0;
}

一个大型的软件项目,可能有几千个,上万个 play,而不只是play1,play2这么简单, 这样就可能有N个类似 play1(); play2(); 这样的声明, 这个时候就需要我们想办法把这样的 play1(); play2(); 另行管理, 而不是把他放在.c文件中, 于是.h 文件出现了。

//test.h
void play1();
void play2();
//test6.cpp
#include <stdio.h>
#include "test.h"

void play2(){
	play1();
}

void play1(){
	play2();
}

int main(){
	play1();
	return 0;
}

例子2

头文件:state.h

源文件:state.cpp

其它源文件:t1.cpp t2.cpp t3.cpp, 这些源文件都包含头文件state.h。

需要定义一个全局变量供这些源文件中使用:

1、在 state.h声明全局变量: extern int a;

2、在state.cpp中定义该全局变量:int a = 10;

这样其它源文件就可以使用该变量了。

注意:这里需要的是“声明”,不是“定义”!根据C++标准的规定,一个变量声明必须同时满足两个条件,否则就是定义:

(1)声明必须使用extern关键字;

(2)不能给变量赋初值。

extern int a;       //声明 
int a;              //定义
int a = 0;          //定义
extern int a = 0;   //定义

头文件中应使用extern关键字声明全局变量(不定义),头文件请不要定义任何变量,那是非常业余的行为。

一般在头文件中用extern声明,在cpp中定义。如果在头文件中定义,如果这个头文件被多个cpp引用,会造成重复定义的链接错误

如果在.cpp里使用static定义,则该变量只在当前cpp文件中有效,在别的文件中无效

在.h里使用static定义,不会进行编译(.h文件不编译),只会在其每个include的cpp文件中包含编译,相当于在.cpp里使用static 定义。

Search

    Post Directory