include怎么关联头文件?头文件如何关联源文件?头文件被重复包含的危害?怎么防止重复包含?

头文件(.h)的功能是一般用来进行声明的(函数,类或变量引用,宏定义)。

源文件(.cpp)是用来进行定义的(函数,类定义,变量定义)。

#include 是在编译器进行编译之前,即在预编译时把它后面所写的那个头文件的内容,完完整整地、 一字不改地包含到当前的源文件中来。

1.源文件如何根据#include来关联头文件

        A)  #include <>

           系统自带的头文件用尖括号括起来,这样编译器会在系统文件目录下查找。

        B) #include “xxx.h” 

          用户自定义的文件用双引号括起来,编译器首先会在用户目录下查找,然后在到C++安装目录(比如VC中可以指定和修改库文件查找路径,Unix和Linux中可以通过环境变量来设定)中查找,最后在系统文件中查找。

  2. 头文件如何来关联源文件

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

把下面的总结一哈:

https://blog.csdn.net/speargod/article/details/84342992

一个工程生成.exe文件需要经历 编译和链接  两大步

而编译又可以分为 预处理 编译 汇编 

预处理就是把 #include 这些玩意的代码 copy替换进来

编译就是  编译器对经过预处理之后的每一个源文件 进行语法 词法分析 检查一哈代码对不对 不对就报错, 对就把代码优化一下生成汇编语言的程序.    注意   源文件  #include 的不都是头文件嘛  ,而头文件里都是 函数,变量的声明  没有写函数, 变量的具体怎么实现,也就是定义.     编译的时候,并不会去找b.cpp文件中的函数实现,只有在link的时候才进行这个工作。我们在b.cpp或c.cpp中用#include “a.h”实际上是引入相关声明,使得编译可以通过,程序并不关心实现是在哪里,是怎么实现的。

然后是汇编 ,汇编就是  汇编器 把汇编代码 转为二进制  机器代码

再是链接

 

在link的时候,需要在makefile里面说明需要连接哪个.o或.obj文件(在这里是b.cpp生成的.o或.obj文件),此时,连接器会去这个.o或.obj文件中找在b.cpp中实现的函数,再把他们build到makefile中指定的那个可以执行文件中。 

不过在VS中,一帮情况下不需要自己写makefile,只需要将需要的文件都包括在project中,VC会自动帮你把makefile写好。 通常,编译器会在每个.o或.obj文件中都去找一下所需要的符号,而不是只在某个文件中找或者说找到一个就不找了。因此,如果在几个不同文件中实现了同一个函数,或者定义了同一个全局变量,链接的时候就会提示“redefined”。    

链接就是把.obj文件链接在一起形成可执行文件  .exe    

我自己想哈  一个工程下面可以有很多源文件   但是 只能有一个源文件下 有那个main 函数   然后 生成可执行文件的过程就是 把那个有那个main函数的源文件main.cpp  里面用到的函数啊  变量啊  都在 别的  .obj文件里 找到   然后把找到的.obj  都跟 main.obj  搞到一起  生成 .exe

 

 

    其实.cpp和.h文件名称没有任何直接关系,很多编译器都可以接受其他扩展名。比如偶现在看到偶们公司的源代码,.cpp文件由.cc文件替代了。 

    在Turbo C中,采用命令行方式进行编译,命令行参数为文件的名称,默认的是.cpp和.h,但是也可以自定义为.xxx等等。 谭浩强老师的《C程序设计》一书中提到,编译器预处理时,要对#include命令进行“文件包含处理”:将file2.c的全部内容复制到#include “file2.c”处。这也正说明了,为什么很多编译器并不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中指定的那个可以执行文件中。 

    在Unix下,甚至可以不在源文件中包括头文件,只需要在makefile中指名即可(不过这样大大降低了程序可读性,是个不好的习惯哦^_^)。在VC中,一帮情况下不需要自己写makefile,只需要将需要的文件都包括在project中,VC会自动帮你把makefile写好。 通常,编译器会在每个.o或.obj文件中都去找一下所需要的符号,而不是只在某个文件中找或者说找到一个就不找了。因此,如果在几个不同文件中实现了同一个函数,或者定义了同一个全局变量,链接的时候就会提示“redefined”。    

   3. 头文件被重复包含的危害

https://www.zhihu.com/question/26872913

 A)   当文件中有对变量的定义时,多次包含该文件这个变量就会被多次定义,这就会报错。

如下:  当文件中有一个对变量的定义

int  value = 10;

当多次包含该文件时,就变成了

int value = 10;

int value = 10;

··· ···

int value = 10;

这样就会出错。

B)  头文件中有定义static变量,就会在每个文件中产生静态变量,逻辑就乱了。

4.怎么防止重复包含

方式一:

#ifndef COMPARE_H

#define COMPARE_H

.......... //头文件具体声明语句

#endif

方式二:

#pragma once

... ... //头文件具体声明语句

第一种方式就是定义一个宏,宏名一般取头文件名       比如头文件叫compare.h   那就叫 COMPARE_H

这种宏是为了防止一个编译单元(cpp文件)重复包含同一个头文件。它在预处理阶段起作用,预处理器发现a.cpp内已经定义过A_H  这个宏的话,在a.cpp中再次发现#include "a.h"的时候就不会把a.h的内容替换进a.cpp了。

而当你写成
#ifndef XXX #define XXX
int a=1;
#endif

包含两次就是
#ifndef XXX #define XXX
int a=1;
#endif
#ifndef XXX #define XXX
int a=1;
#endif
第一次中,由于没有定义XXX,所以做了两件事,定义XXX,然后int a;
第二次中,由于已经定义XXX,所以啥都不做
 

而“#pragma once”是预处理阶段的,保证一个cpp中一个这个类,防止重复导入同一个类,但是你是多了cpp当然多次导入了,每个cpp单独工作生成,就是有限联系而已

是一个比较常用的C/C++杂注,只要在头文件的最开始加入这条杂注,就能够保证头文件只被编译一次。

“#pragma once”的用处就是:

ww.h
#pragma once
const int s = 12;


然后你再ww.cpp中


#include "stdafx.h"
#include "ww.h"
#include "ww.h"
#include "ww.h"
#include "ww.h"
没有#pragma once的话,s会重定义 多次,有了#pragma once就保证头文件只被编译一次,就只有一个s。

比较

#ifndef的方式依赖于宏名字不能冲突,这不光可以保证同一个文件不会被包含多次,也能保证内容完全相同的两个文件不会被不小心同时包含。当然,缺点就是如果不同头文件的宏名不小心“撞车”,可能就会导致头文件明明存在,编译器却硬说找不到声明的状况。

#pragma once则由编译器提供保证:同一个文件不会被编译多次。注意这里所说的“同一个文件”是指物理上的一个文件,而不是指内容相同的两个文件。带来的好处是,你不必再费劲想个宏名了,当然也就不会出现宏名碰撞引发的奇怪问题。对应的缺点就是如果某个头文件有多份拷贝,本方法不能保证他们不被重复包含。当然,相比宏名碰撞引发的“找不到声明”的问题,重复包含更容易被发现并修正。

方式一由语言支持所以移植性好,方式二 可以避免名字冲突

#pragma once方式产生于#ifndef之后,因此很多人可能甚至没有听说过。目前看来#ifndef更受到推崇。因为#ifndef受语言天生的支持,不受编译器的任何限制;而#pragma once方式却不受一些较老版本的编译器支持,换言之,它的兼容性不够好。也许,再过几年等旧的编译器死绝了,这就不是什么问题了。

猜你喜欢

转载自blog.csdn.net/speargod/article/details/83757512