头文件
在c++中,我们经常需要调用各种函数、对象、结构体。例如我们写一个最简单的两个数字相加的的函数,文件名称为int_plus.cc:
int int_plus(const int a, const int b){
return a + b;
}
那么我们怎么在主程序中调用它呢?我们只需要在主程序中定义一个同名的函数就行,在编译时,会把各个.cc文件全部编译成二进制,然后通过函数名链接起来。
int int_plus(const int a, const int b);
int main()
{
int a = 3;
int b = 4;
int c = int_plus(a,b);
std::cout << c << std::endl;
return 0;
}
这里说一个重要的结论:
这种调用方法是唯一的方法!
这种调用方法是唯一的方法!
这种调用方法是唯一的方法!
但实际写代码时,我们可能会调用非常多的函数,同一个函数也可能被不同的代码反复调用,每次调用我们都写一个同名函数不仅繁琐而且容易出错。那么有没有什么办法写简单一些呢?有,用头文件。
头文件是一个给出函数,对象、结构体的定义的文件,一般不在头文件中写具体的逻辑代码。
在上面的例子中,我们定义一个头文件int_plus.h,代码是:
int int_plus(const int a, const int b);
我们在调用相关的函数时,只需要写上:
#include "int_plus.h"
int main()
{
int a = 3;
int b = 4;
int c = int_plus(a,b);
std::cout << c << std::endl;
return 0;
}
需要注意的是,对于c++自有的模块,一般用尖括号,写成
#include <string.h>
#include 是一个宏表达式,在预编译阶段,会把include的头文件中的所有内容复制到代码的开头。
虽然我们用了include和头文件来用于调用,但是在实际编译中,会把头文件的内容复制到代码开头,本质上还是定义了一个同名函数。所以上面说定义同名函数是唯一的方法。
一般在定义写头文件时,会使用#ifdef来定义一个宏
例如在上面的例子中,会写成
#ifndef INT_PLUS_H
#define INT_PLUS_H
int int_plus(const int a, const int b);
#endif
它的作用是为了防止重复复制,例如,我们有两个头文件int_plus.h 和 int_plus_v2.h。 其中int_plus_v2.h的代码如下:
#ifndef INT_PLUS_V2_H
#define INT_PLUS_V2_H
#include "int_plus.h"
int int_plus_v2(const int a, const int b);
#endif
在main中同时有
#include "int_plus.h"
#include "int_plus_v2.h"
如果没有定义ifdef的宏,在预编译的时候会导致int_plus.h被复制到main文件中2次,从而报错。而有了#ifdef 以后,在第二次复制的时候由于宏INT_PLUS_H已经存在,所以会认为int_plus.h文件是空的,不会重复复制。
值得一提的是,虽然头文件和源文件经常出现在一个路径下,但其实并没有这个必要。头文件是在预编译的时候用于复制函数名,而源文件则是在编译和链接环节生效。