C++编译流程

编译器其实就是一个翻译器,把我们的文件内容翻译成机器能够看懂的指令,但如何合理翻译是核心。

C语言编译

需要经过以下几步:

  1. 词法分析:扫描代码,确定单词类型,比如是变量还是函数,是标识符还是运算符等等,这样操作后每个token都有自己的性质
  2. 语法分析:根据语法规则构建分析树
  3. 语义分析:主要是检查代码里是否有语义错误,比如函数返回值是否一致/是否访问超出作用域的变量/变量函数是否已经声明等
  4. 生成中间代码
  5. 汇编器生成目标机器语言

在这里插入图片描述

C++编译流程

在这里插入图片描述

预处理

将一些预处理指令的东西进行处理,比如#include、#pragma #define
对于include而言,预处理器会直接打开这个文件,然后将其copy进我们的cpp文件里。 (宏是直接进行字符串替换的)
此时生成的文件是.i文件

编译

通过编译器和汇编器将.cpp文件编译成.o文件,这里的.o其实就是一些01码,为了方便理解,可以先让编译器输出汇编指令(其实本质都是差不多的,做过CPU的应该知道汇编转01码怎么做)
换句话说,如果代码没有语法错误,编译是不应该报错的,比如缺少main函数入口等

// MyClass.cppclass MyClass {
public:int value;void setValue(int v) {value = v;helper();  // 调用自己的成员函数}void helper() {// 空函数,只为了演示调用过程}
};

实际编译后.o:

[ MyClass.o ] ←←←←← 编译器输出
┌──────────────────────────────┐
│          .text 段            │←─ 代码段(真正的机器码存放区)
│                              │
│ 0x0000: MyClass::helper()    │←─ helper 的汇编已生成在此位置
│        push rbp              │
│        mov rsp, rbp          │
│        ...                   │
│        ret                   │
│                              │
│ 0x0040: MyClass::setValue()  │←─ setValue 的汇编在这里
│        mov [this], v         │
│        call helper()         │←─ 这条 call 指令地址还没填
└──────────────────────────────┘┌──────────────────────────────┐
│         符号表(.symtab)     │←─ 存储函数名、地址、段类型等元信息
│                              │
│ _ZN7MyClass6helperEv  → 0x0000helper() 的地址
│ _ZN7MyClass8setValueEi → 0x0040setValue() 的地址
└──────────────────────────────┘

附上如何只编译文件+看汇编结果

 g++ -c -O0 -fno-inline -o main.o main.cppobjdump -d main.o  

需要注意的是,每个.o文件独立,函数留的地址也是相对地址,链接器还需要解决相对地址转绝对地址的问题。

链接

那么问题来了,如果我只有一个cpp文件,那么到编译这一步就可以了。但是在大型工程文件里,我们往往是有多个模块的,多个模块之间彼此还有调用关系,如何能生成正确的指令呢?其实就是依赖链接器,将多个cpp的.o文件给链接在一起。
多个模块之间的调用关系有:

  1. 你去访问别人的变量
  2. 调用别人的成员函数:在汇编指令中这一句话是call xxx,这个xxx就是函数签名
    如果你在一个文件里声明并且定义了函数func,在另一个文件里也定义了func,对于include了这两个文件的文件来说,链接器不知道要链接具体哪一个,因此会报错称重复定义xxx。
    举个具体的例子
    MyClass.h代码:
class MyClass {
public:int value;void setValue(int v);void helper();
};

MyClass.cpp代码:

#include "MyClass.h"
void MyClass::setValue(int v) {value = v;helper();
}
void MyClass::helper() { }

main的cpp代码:

#include "MyClass.h"
int main() {MyClass obj;obj.setValue(42);return 0;
}

main的汇编:

0000000000000000 <main>:0:	55                   	push   %rbp1:	48 89 e5             	mov    %rsp,%rbp4:	48 83 ec 30          	sub    $0x30,%rsp8:	e8 00 00 00 00       	callq  d <main+0xd>d:	48 8d 45 fc          	lea    -0x4(%rbp),%rax11:	ba 2a 00 00 00       	mov    $0x2a,%edx16:	48 89 c1             	mov    %rax,%rcx19:	e8 00 00 00 00       	callq  1e <main+0x1e>1e:	b8 00 00 00 00       	mov    $0x0,%eax23:	48 83 c4 30          	add    $0x30,%rsp27:	5d                   	pop    %rbp28:	c3                   	retq   
0x08构造初始化
0x16设置this指针
0x19调用setValue

编译器在生成这段机器码的时候,先写了一条机器指令,但是不知道setValue的地址,因此在e8后面跟的都是00000000。同时在.o的重定位表里添加记录:

偏移地址:0x19
类型:CALL
目标符号:_ZN7MyClass8setValueEi

myclass.o的汇编

0000000000000000 <_ZN7MyClass8setValueEi>:0:	55                   	push   %rbp1:	48 89 e5             	mov    %rsp,%rbp4:	48 83 ec 20          	sub    $0x20,%rsp8:	48 89 4d 10          	mov    %rcx,0x10(%rbp)c:	89 55 18             	mov    %edx,0x18(%rbp)f:	48 8b 45 10          	mov    0x10(%rbp),%rax13:	8b 55 18             	mov    0x18(%rbp),%edx16:	89 10                	mov    %edx,(%rax)18:	48 8b 4d 10          	mov    0x10(%rbp),%rcx1c:	e8 07 00 00 00       	callq  28 <_ZN7MyClass6helperEv>21:	90                   	nop22:	48 83 c4 20          	add    $0x20,%rsp26:	5d                   	pop    %rbp27:	c3                   	retq   0000000000000028 <_ZN7MyClass6helperEv>:28:	55                   	push   %rbp29:	48 89 e5             	mov    %rsp,%rbp2c:	48 89 4d 10          	mov    %rcx,0x10(%rbp)30:	90                   	nop31:	5d                   	pop    %rbp32:	c3                   	retq   33:	90                   	nop34:	90                   	nop35:	90                   	nop36:	90                   	nop37:	90                   	nop38:	90                   	nop39:	90                   	nop3a:	90                   	nop3b:	90                   	nop3c:	90                   	nop3d:	90                   	nop3e:	90                   	nop3f:	90                   	nop

因此,在链接器处理.o时会读取每个.o文件的重定位表,当看到

main.o:offset 0x19 → CALL → _ZN7MyClass8setValueEi

记录时,就会查找所有.o文件中是否有这个定义的,然后获取它的地址,并且计算当前call指令的位置到这个地址的相对偏移。每个.o文件会有符号表,用来存储每个函数的入口地址,方便补地址

动态链接和静态链接

此前提到的都是静态链接,直接打包进可执行文件中。那什么是动态链接呢?动态链接就是在运行的时候将程序用到的函数、库从外部共享库中加载进来。
优势就是节省空间,只需要加载一份,可以共享。支持更新和修复,但是稳定性和独立性差,性能也不好

生成exe文件

链接需要为exe指明程序的入口位置,这也就是main的作用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/74107.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python学智能算法(八)|决策树

【1】引言 前序学习进程中&#xff0c;已经对KNN邻近算法有了探索&#xff0c;相关文章链接为&#xff1a; python学智能算法&#xff08;七&#xff09;|KNN邻近算法-CSDN博客 但KNN邻近算法有一个特点是&#xff1a;它在分类的时候&#xff0c;不能知晓每个类别内事物的具…

使用 OpenCV 拼接进行图像处理对比:以形态学操作为例

图像处理在计算机视觉中起着至关重要的作用&#xff0c;而 OpenCV 作为一个强大的图像处理库&#xff0c;提供了丰富的函数来实现各类图像处理任务。形态学操作&#xff08;Morphological Operations&#xff09;是其中常用的技术&#xff0c;尤其适用于二值图像的处理。常见的…

版本控制器Git ,Gitee如何连接Linux Gitee和Github区别

&#x1f4d6; 示例场景 假设你和朋友在开发一个「在线笔记网站」&#xff0c;代码需要频繁修改和协作&#xff1a; 只用本地文件管理 每次修改后手动复制文件&#xff0c;命名为 v1.html、v2.html 问题&#xff1a;无法追踪具体改动内容&#xff1b;多人修改易冲突&#xff1…

使用DeepSeek翻译英文科技论文,以MarkDown格式输出,使用Writage 3.3.1插件转换为Word文件

一、使用DeepSeek翻译英文科技论文&#xff0c;以MarkDown格式输出 以科技论文“Electrical Power System Sizing within the Numerical Propulsion System Simulation”为例。 关于Writage 3.3.1的进一步了解&#xff0c;可发送邮件至邮箱pyengine163.com. 首先&#xff0c;打…

【NPU 系列专栏 3.0 -- scale-out 和 scale-in 和 scale-up 和 scale-down

文章目录 Overview1. Scale-out 和 Scale-in (横向扩展/缩减)举例:AI SoC 中的 Scale-out 和 Scale-in2. Scale-up 和 Scale-down (纵向扩展/缩减)举例:AI SoC 中的 Scale-up 和 Scale-down对比总结Overview 本文会 以 AI SoC 为例 详细介绍什么是 scale-out 和 scale-i…

Spring Boot 集成 Quartz 实现定时任务(Cron 表达式示例)

Spring Boot 集成 Quartz 实现定时任务&#xff08;Cron 表达式示例&#xff09; 前言1. 添加 Quartz 依赖2. 创建 Quartz 任务3. 配置 Quartz 任务调度4. 启动 Spring Boot 观察定时任务执行5. Quartz Cron 表达式详解6. 结论 前言 在 Spring Boot 项目中&#xff0c;我们经常…

智能汽车图像及视频处理方案,支持视频智能拍摄能力

美摄科技&#xff0c;作为智能汽车图像及视频处理领域的先行者&#xff0c;凭借其卓越的技术实力和前瞻性的设计理念&#xff0c;为全球智能汽车制造商带来了一场视觉盛宴的革新。我们自豪地推出——美摄科技智能汽车图像及视频处理方案&#xff0c;一个集高效性、智能化、画质…

QPrintDialog弹出慢的问题

开发环境 操作系统: openkylin2qt版本 : 5.15.10排查过程 首先看下问题的现象, 问题现象 复现问题的demo很简单,只能是从跟踪qt代码方面入手 void MainWindow::on_pushButton_clicked(){QPrinter printer;QPrintDialog dialog(&printer,this);dialog.exec();} 现在需要找一…

VLAN:逻辑隔离冲突网络的详细讲解

1. VLAN的基本概念 VLAN&#xff08;Virtual Local Area Network&#xff0c;虚拟局域网&#xff09; 是一种将物理网络划分为多个逻辑独立网络的技术。通过VLAN&#xff0c;不同逻辑网络可以在同一物理网络基础设施上运行&#xff0c;彼此隔离&#xff0c;互不影响。 核心功能…

投影算子(Projection Operator)的定义、性质、分类以及应用

文章目录 1. 投影算子的定义2. 投影算子的几何意义3. 一些简单的例子例 1&#xff1a;二维平面上的投影例 2&#xff1a;投影到一条任意方向的直线例 3&#xff1a;三维空间中投影到一个平面 4. 投影算子的性质4.1、幂等性&#xff08;Idempotency&#xff09;&#xff1a; P 2…

java使用Apache POI 操作word文档

项目背景&#xff1a; 当我们对一些word文档&#xff08;该文档包含很多的标题比如 1.1 &#xff0c;1.2 &#xff0c; 1.2.1.1&#xff0c; 1.2.2.3&#xff09;当我们删除其中一项或者几项时&#xff0c;需要手动的对后续的进行补充。该功能主要是对标题进行自动的补充。 具…

接收与发送ipv6数据包

一、ipv6的概念 IPv6 是英文 “Internet Protocol Version 6”&#xff08;互联网协议第 6 版&#xff09;的缩写&#xff0c;是互联网工程任务组&#xff08;IETF&#xff09;设计的用于替代 IPv4 的下一代 IP 协议&#xff0c;其地址数量号称可以为全世界的每一粒沙子编上…

龙虎榜——20250321

今日A股龙虎榜方向分析 根据2025年3月21日龙虎榜数据&#xff08;涨停56家&#xff0c;跌停31家&#xff09;&#xff0c;市场呈现结构性分化行情&#xff0c;资金聚焦海洋经济、机器人、锂电等主线&#xff0c;部分个股遭机构大幅抛售。以下是具体方向解析&#xff1a; 一、资…

springboot milvus search向量相似度查询 踩坑使用经验

1.前提提要&#xff1a;java的pom 版本为&#xff1a;2.4.9 milvus 版本是&#xff1a;2.4.13-hotfix 2.先来工具类方法 /*** 向量搜索* param client* param query* return*/public SearchResp search(NonNull MilvusClientV2 client, NonNull VectorCondition query) {final …

[网络安全] 滥用Azure内置Contributor角色横向移动至Azure VM

本文来源于团队的超辉老师&#xff0c;其系统分析了Azure RBAC角色模型及其在权限滥用场景下的攻击路径。通过利用AADInternals工具提升用户至Contributor角色&#xff0c;攻击者可在Azure VM中远程执行命令&#xff0c;创建后门账户&#xff0c;实现横向移动。文中详述了攻击步…

Android Compose 基础布局之 Box 和 Stack 源码深度剖析(九)

Android Compose 基础布局之 Box 和 Stack 源码深度剖析 一、引言 1.1 Android 开发中布局的重要性 在 Android 应用开发里&#xff0c;布局是构建用户界面&#xff08;UI&#xff09;的关键环节。良好的布局设计能够提升用户体验&#xff0c;使应用界面更加美观、易用且具有…

知识蒸馏:让大模型“瘦身“而不失智慧的魔术

引言&#xff1a;当AI模型需要"减肥" 在人工智能领域&#xff0c;一个有趣的悖论正在上演&#xff1a;大模型的参数规模每年以10倍速度增长&#xff0c;而移动设备的算力却始终受限。GPT-4的1750亿参数需要价值500万美元的GPU集群运行&#xff0c;但现实中的智能设备…

多路FM调频广播解调器:多路电台FM广播信号一体化解调处理方案

多路FM调频广播解调器&#xff1a;多路电台FM广播信号一体化解调处理方案 支持OEM型号开放式协议支持二次开发设计 北京海特伟业科技有限公司任洪卓发布于2025年3月21日 在信息传播领域&#xff0c;FM调频广播媒体以其独特的优势持续发挥着重要作用。为了应对日益增长的多路…

如何在Spring Boot中设置HttpOnly Cookie以增强安全性

引言 在Web开发中,Cookie是用于在客户端和服务器之间传递信息的重要机制。然而,Cookie的安全性一直是一个备受关注的问题。特别是当Cookie中存储了敏感信息(如会话ID)时,如何防止这些信息被恶意脚本窃取就显得尤为重要。HttpOnly属性是增强Cookie安全性的一种有效手段。本…

LangManus:新一代开源智能体框架如何让AI开发更简单?

你是否想过&#xff0c;代码生成、数据分析甚至系统调试&#xff0c;都能由一个“AI助手”自动完成&#xff1f;最近&#xff0c;一款名为LangManus的开源项目在开发者社区掀起热议。它不只是一个工具库&#xff0c;更是一个能自主思考、执行复杂任务的智能体框架。无论是企业内…