news 2026/7/28 19:49:59

C++ 中到底是应该include .h文件还是应该include .cpp文件

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C++ 中到底是应该include .h文件还是应该include .cpp文件

在阅读一个较大的解决方案中,对于其他文件夹下的.h和.cpp文件,有时候#include“XXX.h”文件,有时候是#include“XXX.cpp”文件,而且二者还不能更换。下面就好好分析一下他们二者的区别。

文章目录

  • 测试
    • 测试:XXX.h和XXX.cpp有没有在解决方案里的差别
  • 探究
    • 预处理(简单替换)
    • 编译和优化(高级语言->汇编语言)
    • 生成目标文件(汇编语言->二进制机器语言)
    • 链接(汇总成一个目标文件)
  • 外部文件夹的h和cpp文件

测试

测试:XXX.h和XXX.cpp有没有在解决方案里的差别

如果.h文件和.cpp文件都已经添加在解决方案里,只要在main的头文件中include对应的.h文件即可。
如果.h文件和.cpp文件不在解决方案里,可能在其他文件夹里,单独include.h文件就会报错“error LNK2019: 无法解析的外部符号”。但是单独include.cpp就能运行了,而此时.cpp里面有没有对应的.h头文件都可以正确运行(因为.h文件里有#pragma once防止多次定义),这个很好解释,include就是把对应的代码拷贝一份进去。拷贝之后,自定义函数的定义本来就在使用前,有没有头文件的声明都可以。为了验证include是不是就是将程序拷贝,做了实验验证。在自定义函数使用前#include“XXX.h”用于函数的声明,在main函数结束之后#include“XXX.cpp”,运行果然正确。
初步结论:说明当.h文件和.cpp文件不在解决方案里的时候,#include就是纯粹的拷贝复制工作。但是当h和cpp文件在解决方案的情况需要进一步验证。同时也说明,cpp文件有没有包含进工程文件的情况是不同的。


探究

按照所有查到的信息都说明一点内容:凡是#include的头文件,都是把对应的文件信息拷贝复制一份进来。显然这个笼统的概念是不对的。

源程序->预处理->编译和优化->生成目标文件->链接->可执行文件
参考之前我转载的3篇博文C++编译与链接的三部曲(强烈推荐看一看)。大致总结如下:


预处理(简单替换)

预处理做如下工作:

预处理器主要负责以下的几处: 1.宏的替换 2.删除注释 3.处理预处理指令,如#include,#ifdef

编译和优化(高级语言->汇编语言)

词法分析 – 识别单词,确认词类;比如int i;知道int是一个类型,是一个关键字以及判断i的名字是否合法。
语法分析 – 识别短语和句型的语法属性;
语义分析 – 确认单词、短语和句型的语义特征;
代码优化 – 修辞、文本编辑;
代码生成 – 生成译文。
内联函数的替换就发生在这一阶段。

编译的另一个重要方面就是编译单元
什么是编译单元呢?简单来说一个cpp文件就是一个编译单元。
在集成式的IDE中,我们往往点击一下运行便可以了,编译的所有工作都交给了IDE去处理,往往忽略了其中的内部流程。
事实上编译每个编译单元(.cpp)时是相互独立的,即每个cpp文件之间是不知道对方的存在的(不考虑#include “xxx.cpp" 这种奇葩的写法)。
编译器会分别将每个编译单元(.cpp)进行编译,生成相应的obj文件,然后链接器会将所有的obj文件进行链接,生成最终可执行文件内部链接与外部链接。

这里能作为单独编译单元的是添加进工程的cpp文件,外部文件夹的cpp文件并不单独成为编译单元。


生成目标文件(汇编语言->二进制机器语言)

汇编过程实际上指把汇编语言代码翻译成目标机器指令的过程。
在最终的目标文件中,编译器把一个cpp编译为目标文件的时候,除了要在目标文件里写入cpp里包含的数据和代码,还要至少提供3个表:

未解决符号表; 导出符号表; 地址重定向表

未解决符号表提供了所有在该编译单元里引用但是定义并不在本编译单元里的符号及其出现的地址;
导出符号表提供了本编译单元具有定义,并且愿意提供给其他编译单元使用的符号及其地址。
地址重定向表提供了本编译单元所有对自身地址的引用的记录。
这就是不同cpp之间的通讯方式。

从这个定义方式上看,主cpp文件和其他所有cpp文件都是平等的关系,只不过主cpp里面包含了main函数而已,而main函数和其他所有函数也是平等的,只不过只有main函数可以作为工程的入口函数而已。


链接(汇总成一个目标文件)

由汇编程序生成的目标文件并不能立即就被执行,其中可能还有许多没有解决的问题。例如,某个源文件中的函数可能引用了另一个源文件中定义的某个符号(如变量或者函数调用等);在程序中可能调用了某个库文件中的函数,等等。所有的这些问题,都需要经链接程序的处理方能得以解决。
由此,我们可以理解了经常报错的一些情况,就是未解决符号表和导出符号表之间没有定义或者重复定义的情况的。


外部文件夹的h和cpp文件

外部文件夹的cpp文件并不能生成单独的编译文件,所以,不参与未解决符号表和导出符号表的生成,而#include外部的h头文件也只是复制进来头文件中的函数声明而已,没有定义。所以当需要使用外部文件夹的cpp文件的时候,直接在头部加上#include cpp文件,或者在头部#include h文件,尾部#include cpp文件,就相当于我们平时写的自定义函数一样。


终于搞明白了,so,Let’s enjoy it~

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/28 19:49:41

暗黑破坏神2存档编辑器完全指南:5分钟学会角色与装备修改

暗黑破坏神2存档编辑器完全指南:5分钟学会角色与装备修改 【免费下载链接】d2s-editor 项目地址: https://gitcode.com/gh_mirrors/d2/d2s-editor 还在为暗黑破坏神2存档损坏而烦恼?想测试新build却不想重新练级?暗黑破坏神2存档编辑…

作者头像 李华
网站建设 2026/7/28 19:46:08

P1972 HH的项链 离线+树状数组

P1972 HH的项链 离线树状数组 这题好像用线段树做有点……超出我的智商了 如果数字范围小于60的话还可以用状压 但是吧1e6有点过分了0.0 今天刚学树状数组,随便写了个线段树经典修改题,就来补这道题了 嘤嘤嘤菜鸡互啄 题意 给出m个询问L,R ,问…

作者头像 李华
网站建设 2026/7/28 19:44:02

FigmaCN终极中文汉化指南:3分钟实现Figma全界面本地化

FigmaCN终极中文汉化指南:3分钟实现Figma全界面本地化 【免费下载链接】figmaCN 中文 Figma 插件,设计师人工翻译校验 项目地址: https://gitcode.com/gh_mirrors/fi/figmaCN 你是否在使用Figma时被英文界面困扰?专业术语难懂、菜单选…

作者头像 李华