C++ 编译过程(附简单实例)
C++ 采用分离编译模式,分离编译指的是,一个程序/项目是由若干个源文件共同实现,编译时先把每个源文件单独编译生成目标文件,再将所有目标文件连接起来,形成单一的可执行文件。
C++ 编译的四个阶段:预处理、编译、汇编和链接。
这里以 g++ 为例,用到的文件分别为 mymath.h、mymath.cpp 和 main.cpp ,代码如下:
// mymath.h
extern int add(int, int);
// mymath.cpp
#include "mymath.h"
// implement func 'add'
int add(int n1, int n2) {return (n1 + n2);
}
// main.cpp
#include <iostream>
#include "mymath.h"
#define ADD1 5
#define ADD2 6int main() {// call func 'add' defined in <mymath.h> file// and printstd::cout << add(ADD1, ADD2) << std::endl;return 0;
}

1. 预处理(Preprocessing)
1)读取C/C++源程序,对其中的伪指令(以#开头的指令)进行处理,包括:
a. 将所有的“#define”删除,并且展开所有的宏定义。
b. 处理所有的条件编译指令,如:“#if”、“#ifdef”、“#elif”、“#else”、“endif”等。这些伪指令的引入使得程序员可以通过定义不同的宏来决定编译程序对哪些代码进行处理。预编译程序将根据有关的文件,将那些不必要的代码过滤掉。
c. 处理 “#include” 预编译指令,将被包含的文件插入到该预编译指令的位置。注意这个过程可能是递归进行的,也就是说被包含的文件可能还包含其他文件。
2)删除所有的注释。
3)添加行号和文件名标识。以便于编译时编译器产生调试用的行号信息及用于编译时产生的编译错误或警告时能够显示行号。
4)保留所有的#pragma编译器指令。
预处理相当于根据预处理指令组装新的C/C++程序。经过预处理,会产生一个没有宏定义,没有条件编译指令,没有特殊符号的输出文件,这个文件的含义同源文件无异,只是内容上有所不同。
【补充】常用的预处理指令包括:
宏定义:#define
文件包含:#include
条件编译:#if、#elif、#ifndef、#ifdef、#endif、#undef
错误信息指令:#error
#line指令
布局控制:#pragma
【注意】预处理不做语法检查。
以 g++ 为例,g++ 使用参数 -E 对源文件进行预处理,并在预处理后退出而不会进行后续的编译操作:
g++ -E mymath.cpp -o mymath.i
g++ -E main.cpp -o main.i
如果头文件和cpp 文件不在同一目录下,可以通过参数 I 来指定。
g++ -E -Iheader_dir src.cpp -o target.i
经过预处理后的文件大小会有一定的增加:
$ wc -l main.cpp main.i13 main.cpp55993 main.i56006 total
$ wc -l mymath.cpp mymath.i7 mymath.cpp17 mymath.i24 total
2.编译(Compilation)
将源文件转换成特定汇编代码(assembly code),在这一阶段会执行语法检查。
以 g++ 为例,使用参数 -S 对预编译后的文件编译生成汇编代码。
g++ -S mymath.i -o mymath.s
g++ -S main.i -o main.s
【注意】
a. 这里的源文件,它既可以是源代码文件,也可以是源代码预处理之后的文件,如果输入文件是源代码文件,那么该命令会同时执行预处理和编译。如果是已经预处理后的文件,那么直接执行编译。
b. 预处理和编译生成的文件都是文本文件,可以直接在文本编辑器中打开并查看。
3.汇编(Assemble)
将汇编代码转换成机器码(machine code),生成可重定位目标程序的目标文件,目标文件是二进制格式,字节编码是机器指令。
【补充】汇编器是将汇编代码转变成机器可以执行的指令,每一个汇编语句几乎都对应一条机器指令。所以汇编器的汇编过程相对于编译器来讲比较简单,它没有复杂的语法,也没有语义,也不需要做指令优化,只是根据汇编指令和机器指令的对照表一一翻译即可。
以 g++ 为例,使用参数 -c 对编译后的文件编译生成汇编代码。
g++ -c mymath.s -o mymath.o
g++ -c main.s -o main.o
4.链接(Linking)
链接过程将多个目标文以及所需的库文件链接成最终的可执行文件(executable file)。
由汇编程序生成的目标文件并不能被立即执行,其中可能还有许多没有解决的问题。例如某个源文件中的函数可能引用了另一个源文件中定义的某个符号(变量或者函数调用等);在程序中可能调用了某个库文件中的函数,诸如此类。这些问题都需要经过链接程序的处理来解决。
例如在上面的例子中,main.cpp 用到的 add 函数,就是在另一个文件 mymain.cpp 中定义的。
链接程序的主要工作就是将有关的目标文件彼此相连接,即将在一个文件中引用的符号同该符号在另外一个文件中的定义连接起来,使得所有的这些目标文件成为一个能够被操作系统装入执行的统一整体。
以 g++ 为例:
g++ main.o mymath.o -o main.out
有时候需要用到第三方库,这个时候可以使用参数 -l:
g++ tmp.o -Ithirdpart_header_dir -Lthirdpart_dir -lthirdpart_lib_name
【最后的补充】按步编译不是必须的,大多数时候 C++ 的编译是这样的:
g++ main.cpp mymath.cpp -o main.out
:)
【关于各阶段生成的文件后缀名】
1.预处理,生成.i的文件;
2.编译,生成 .s 文件.s;
3.汇编,生成.o的文件;
4.链接,生成可执行程序 .o。
最开始我以为输出文件的命名其实是在参数 -o 后自定义的,尝试修改后缀为 “.p1” 或者其他自定义后缀后,发现继续执行下一阶段的时候会提示:
'linker' input unused [-Wunused-command-line-argument]
也就是说,编译器 g++ 会检查命令行中指定的输入文件的后缀名,以此来识别文件类型,暂时没有找到相关资料,后续补充。
相关文章:
C++ 编译过程(附简单实例)
C 采用分离编译模式,分离编译指的是,一个程序/项目是由若干个源文件共同实现,编译时先把每个源文件单独编译生成目标文件,再将所有目标文件连接起来,形成单一的可执行文件。 C 编译的四个阶段:预处理、编译…...
ThingsBoard教程(五四):规则节点解析 Azure IoT Hub Node, RabbitMQ Node
Azure IoT Hub Node Since TB Version 2.5.3 配置 主题 - 获取有关IoT Hub主题的更多信息,请使用以下链接。主机名 - Azure IoT Hub主机名。设备ID - 来自Azure IoT Hub的设备ID。凭据 - Azure IoT Hub连接凭据。可以是共享访问签名或PEM格式证书。Azure IoT Hub支持不同的…...
元素偏移量offset
文章目录 1. offset概述2. offset与style的区别 1. offset概述 offset就是偏移量,我们使用offset系列相关属性可以动态的得到该属性的位置(偏移)、大小等。 element.offsetParent 返回作为该元素带有定位的父级元素,如果父级都没…...
如何让自动化测试框架更自动化?
一、引言 对于大厂的同学来说,接口自动化是个老生常谈的话题了,毕竟每年的MTSC大会议题都已经能佐证了,不是大数据测试,就是AI测试等等(越来越高大上了)。不可否认这些专项的方向是质量智能化发展的方向&…...
无屏幕实现连接树莓派
无屏幕实现连接树莓派 欢迎来到我的博客!今天我将与大家分享如何无需使用屏幕,实现与树莓派的连接。对于那些在树莓派项目中不方便使用屏幕的人来说,这将是一个有用的技巧。 材料清单 在开始之前,让我们先准备好所需的材料&…...
【Android】AMS(一)系统启动流程
前言 AMS(Activity Manager Service)即活动管理器服务,是Android系统中的一个核心服务。它主要负责管理应用程序的生命周期,包括启动应用程序、切换应用程序、管理任务栈等。 Android启动流程 Android程序的启动流程可以概括为…...
FineBI6.0基础学习第一课 数据门户
PC端门户使用示例 首先,以管理员身份登录FineBI系统,安装数据门户,安装步骤见官网 新建一个数据门户...
如何部署项目到Tomcat + 第一个Servlet程序
博主简介:想进大厂的打工人博主主页:xyk:所属专栏: JavaEE初阶 目录 文章目录 一、Tomcat 1.1 Tomcat是什么 1.2 下载安装 1.3 部署项目 二、第一个Servlet程序 2.1 Servlet是什么 2.2 创建Maven项目 2.3 引入依赖 2.4 创建目录 2.5 编写类方法 2.6 打包…...
牛客刷题(HTML-Day1)
第一题: 1.下列代码在页面中显示的内容为( ) <!DOCTYPE html> <html> <body> <p>hello<q>html</q></p> </body> </html> A hello“html” B hello html C hello“”html D 其他几…...
性能测试如何入门?熬夜7天整理出这一份3000字超全学习指南
赶鸭子上架要我搞性能测试,怎么办? 我第一次真正意义上搞性能测试是在2014年。项目组要求搞性能测试,我之前也没搞过,对服务端也不熟悉。就那么一脸懵逼地开始搞性能。当时我连linux上有哪些能看系统资源的命令都不知道。稀里糊涂…...
信息安全实践1.2(重放攻击)
前言 这个实验是看一本书做的,就是李华峰老师的书——《Metasploit Web 渗透测试实战》,我之前写过一篇Slowloris DoS攻击的博客,也是看这本书写的,总的来说,有用处。这篇博客其实也只是很浅显的去做一下重放攻击。 要…...
上海亚商投顾:沪指高开高走 地产股迎来久违反弹
上海亚商投顾前言:无惧大盘涨跌,解密龙虎榜资金,跟踪一线游资和机构资金动向,识别短期热点和强势个股。 市场情绪 三大指数今日高开高走,沪指午后涨近1%,深成指、创业板指涨超1.2%,上证50盘中大…...
Vim学习笔记【Ch02】
Vim学习笔记 系列笔记链接Ch02 Buffers, Windows, TabsBuffers什么是buffer查看所有bufferbuffer之间的切换删除buffer退出所有窗口 Windows窗口的创建窗口切换快捷键其他快捷键 Tabs什么是tabtab相关命令 window和buffer结合的3D移动小结 系列笔记链接 Ch00,Ch01 …...
《低代码指南》——低代码维格云能源行业解决方案
目录 典型场景介绍: 一、能源资产管理 二、碳核查 三、配电运营 总 结: 从业界实际情况来看,流程建设本身是一个对业务现实进行抽象的过程,这个过程即使不考虑软件开发的门槛,对于很多客户而言也是个涉及较长周期的复杂工作,往往需要咨询专家或专业公司帮助其建设内…...
【自制C++深度学习推理框架】Layer的设计思路
Layer的设计思路 Layer的抽象 如果将深度学习中的所有层分为两类, 那么肯定是"带权重"的层和"不带权重"的层。 基于层的共性,我们定义了一个Layer的基类,提供了一些基本接口,并可以通过继承和多态机制实现不同类型的L…...
Rust每日一练(Leetday0011) 下一排列、有效括号、搜索旋转数组
目录 31. 下一个排列 Next Permutation 🌟🌟 32. 最长有效括号 Longest Valid Parentheses 🌟🌟🌟 33. 搜索旋转排序数组 Search-in-rotated-sorted-array 🌟🌟 🌟 每日一练刷…...
STL --- 五. 函数对象 Function Objects
目录 1、函数对象的定义和作用 2、函数对象的分类和使用 3、std 常用的函数对象 4、函数对象的适配器 5、std 算法和函数对象区别 1、函数对象的定义和作用 STL(Standard Template Library)中的函数对象(Functor)是一种重载…...
Java IO 流操作详解
Java IO 流操作详解 一、简介1. 什么是IO流2. IO流的分类3. IO流的作用 二、Java IO流的输入操作1. 文件输入流2. 字节输入流3. 缓冲输入流4. 对象输入流 三、Java IO流的输出操作1. 文件输出流2. 字节输出流3. 缓冲输出流4. 对象输出流 四、Java IO流的常用方法解析1. 字节读写…...
Halcon 形状匹配参数详解
find_shape_model(Image : : ModelID, AngleStart, AngleExtent, MinScore, NumMatches, MaxOverlap, SubPixel, NumLevels, Greediness : Row, Column, Angle, Score) find_shape_model(Image : : //搜索图像 ModelID, //模板句柄 AngleStart, // 搜索时的起始角度 AngleExte…...
C++11强类型枚举
C11引入了强类型枚举(enum class),也称为枚举类。 强类型枚举是一种更加类型安全的枚举类型,相对于传统的枚举类型,强类型枚举可以提供更好的安全性和可读性。 强类型枚举的格式如下: enum class 枚举名 …...
Linux链表操作全解析
Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表?1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...
elementUI点击浏览table所选行数据查看文档
项目场景: table按照要求特定的数据变成按钮可以点击 解决方案: <el-table-columnprop"mlname"label"名称"align"center"width"180"><template slot-scope"scope"><el-buttonv-if&qu…...
【Elasticsearch】Elasticsearch 在大数据生态圈的地位 实践经验
Elasticsearch 在大数据生态圈的地位 & 实践经验 1.Elasticsearch 的优势1.1 Elasticsearch 解决的核心问题1.1.1 传统方案的短板1.1.2 Elasticsearch 的解决方案 1.2 与大数据组件的对比优势1.3 关键优势技术支撑1.4 Elasticsearch 的竞品1.4.1 全文搜索领域1.4.2 日志分析…...
go 里面的指针
指针 在 Go 中,指针(pointer)是一个变量的内存地址,就像 C 语言那样: a : 10 p : &a // p 是一个指向 a 的指针 fmt.Println(*p) // 输出 10,通过指针解引用• &a 表示获取变量 a 的地址 p 表示…...
【深度学习新浪潮】什么是credit assignment problem?
Credit Assignment Problem(信用分配问题) 是机器学习,尤其是强化学习(RL)中的核心挑战之一,指的是如何将最终的奖励或惩罚准确地分配给导致该结果的各个中间动作或决策。在序列决策任务中,智能体执行一系列动作后获得一个最终奖励,但每个动作对最终结果的贡献程度往往…...
AxureRP-Pro-Beta-Setup_114413.exe (6.0.0.2887)
Name:3ddown Serial:FiCGEezgdGoYILo8U/2MFyCWj0jZoJc/sziRRj2/ENvtEq7w1RH97k5MWctqVHA 注册用户名:Axure 序列号:8t3Yk/zu4cX601/seX6wBZgYRVj/lkC2PICCdO4sFKCCLx8mcCnccoylVb40lP...
机器学习的数学基础:线性模型
线性模型 线性模型的基本形式为: f ( x ) ω T x b f\left(\boldsymbol{x}\right)\boldsymbol{\omega}^\text{T}\boldsymbol{x}b f(x)ωTxb 回归问题 利用最小二乘法,得到 ω \boldsymbol{\omega} ω和 b b b的参数估计$ \boldsymbol{\hat{\omega}}…...
VSCode 使用CMake 构建 Qt 5 窗口程序
首先,目录结构如下图: 运行效果: cmake -B build cmake --build build 运行: windeployqt.exe F:\testQt5\build\Debug\app.exe main.cpp #include "mainwindow.h"#include <QAppli...
Axure零基础跟我学:展开与收回
亲爱的小伙伴,如有帮助请订阅专栏!跟着老师每课一练,系统学习Axure交互设计课程! Axure产品经理精品视频课https://edu.csdn.net/course/detail/40420 课程主题:Axure菜单展开与收回 课程视频:...
比特币:固若金汤的数字堡垒与它的四道防线
第一道防线:机密信函——无法破解的哈希加密 将每一笔比特币交易比作一封在堡垒内部传递的机密信函。 解释“哈希”(Hashing)就是一种军事级的加密术(SHA-256),能将信函内容(交易细节…...
