cpp头文件和源文件的作用

⌚Time: 2022-04-21 00:07:34

👨‍💻Author: Jack Ge

c++语言支持“分别编译”(separatecompilation)。对于一个程序,可以将实现它的源码放在多个cpp文件中独立进行编译,之后只需要将编译生成的各个目标文件链接到一起就可以了

对于在一个文件中定义的函数

a.cpp


void fun(){

    ...

}

若要在另外的文件中使用,只需要使用之前,对此函数进行声明,就可以使用了

b.cpp


void fun();

int main(){

fun();

return 0;

}

g++ a.cpp b.cpp -o a.exe

./a.exe

其中的原因,在编译时对于没有定义的函数或变量,如果有对应的声明,就会等到链接阶段再去寻找他的定义,如果能够从别的源文件生成的目标文件中找到,就可以成功生成程序,如果别的目标文件中还是没有找到对其进行的定义,就会出错。

对于定义与声明,"定义"就是把一个符号完完整整地描述出来:它是变量还是函数,返回什么类型,需要什么参数等等。而"声明"则只是声明这个符号的存在。对于一个符号,声明可以有多次,而定义只能有一次

如果在源文件中有成百上千的函数,我们是无法记住每一个声明的。这时就可以使用一个头文件来包含它们全部的声明,之后在使用这些函数的源文件中包含此头文件,这样就相当于在源文件中声明了这些函数,之后再与实现了这些函数的源文件或者库文件一起编译链接就可以了

a.cpp


void fun1(){

}

void fun2(){

}

b.cpp


void fun3(){

}

void fun4(){

}

c.h


void fun1();

void fun2();

void fun3();

void fun4();

d.cpp


#include "c.h"

int main(){

fun1();

fun2();

return 0;

}

g++ a.cpp b.cpp d.cpp -o a.exe

./a.exe

头文件中,只能存在变量或者函数的声明,而不要放定义,如下面是正确的

test.h


extern int a;

如果是这种

test.h


int a;

而被多个源文件包含,就会导致重复定义而在链接阶段出错

但是以下情况在头文件内可以存放定义

在头文件中定义类和结构体不会有重复定义的问题,但是使用结构体、类在头文件中去定义一个变量,并且被多个文件包含才会导致重复定义,如

test.h


class CTest{

    int a;

};//正确

CTest ct;//错误,会导致重复定义

不要将头文件加入VS等IDE的项目列表,因为#include指令会管理头文件。IDE的项目列表实际上也是编译列表,项目里面的源文件会进行编译,而不属于项目里面的源文件,不会进行编译。

程序生成的阶段:

预处理(-E):

头文件参与预编译,主要进行文件包含、条件编译、宏替换等工作

编译(-S):

源文件参与编译,进行语法语义分析,生成汇编代码(.s文件)

汇编(-c):

将汇编代码转换成为机器可执行的二进制目标文件

链接:

链接阶段主要解决多个文件之间符号引用的问题,链接器使用目标文件和库文件,去掉无用符号表(大概就是头文件中声明而从未使用的各种函数和变量),将所有目标文件链接到一起,最终生成可执行文件

避免重复定义符号的办法?

头文件只应该包含符号的声明,而在源文件中进行定义和实现。这样在多个模块包含头文件时,只是对该符号进行了多次声明,并且只在它的源文件中定义了一次。

避免重复包含头文件的方法?

对于MSVC编译器,在头文件中使用


#pragma once

可以让头文件只被包含一次

对于gcc编译器,可以使用


#ifndef _A_H_

#define _A_H_

...



#endif

的写法避免头文件被重复包含