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 枚举名 …...
R语言AI模型部署方案:精准离线运行详解
R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...
2024年赣州旅游投资集团社会招聘笔试真
2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...
1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...
鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南
1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发,使用DevEco Studio作为开发工具,采用Java语言实现,包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...
LOOI机器人的技术实现解析:从手势识别到边缘检测
LOOI机器人作为一款创新的AI硬件产品,通过将智能手机转变为具有情感交互能力的桌面机器人,展示了前沿AI技术与传统硬件设计的完美结合。作为AI与玩具领域的专家,我将全面解析LOOI的技术实现架构,特别是其手势识别、物体识别和环境…...
tauri项目,如何在rust端读取电脑环境变量
如果想在前端通过调用来获取环境变量的值,可以通过标准的依赖: std::env::var(name).ok() 想在前端通过调用来获取,可以写一个command函数: #[tauri::command] pub fn get_env_var(name: String) -> Result<String, Stri…...
【Kafka】Kafka从入门到实战:构建高吞吐量分布式消息系统
Kafka从入门到实战:构建高吞吐量分布式消息系统 一、Kafka概述 Apache Kafka是一个分布式流处理平台,最初由LinkedIn开发,后成为Apache顶级项目。它被设计用于高吞吐量、低延迟的消息处理,能够处理来自多个生产者的海量数据,并将这些数据实时传递给消费者。 Kafka核心特…...
aardio 自动识别验证码输入
技术尝试 上周在发学习日志时有网友提议“在网页上识别验证码”,于是尝试整合图像识别与网页自动化技术,完成了这套模拟登录流程。核心思路是:截图验证码→OCR识别→自动填充表单→提交并验证结果。 代码在这里 import soImage; import we…...
Selenium 查找页面元素的方式
Selenium 查找页面元素的方式 Selenium 提供了多种方法来查找网页中的元素,以下是主要的定位方式: 基本定位方式 通过ID定位 driver.find_element(By.ID, "element_id")通过Name定位 driver.find_element(By.NAME, "element_name"…...
Python异步编程:深入理解协程的原理与实践指南
💝💝💝欢迎莅临我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 持续学习,不断…...
