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