c++程序编译过程及相关概念

2023-05-16

编译

把源文件中的源代码翻译成机器语言,保存到目标文件中。如果编译通过,就会把CPP转换成OBJ文件。

编译单元:

每个cpp就是一个编译单元,每个编译单元相互之间是独立且相互不知的一个编译单元(Translation Unit)是指一个.cpp文件以及这所include的所有.h文件,.h文件里面的代码将会被扩展到包含它的.cpp文件里,然后编译器编译该.cpp文件为一个.obj文件,后者拥有PE(Portable Executable,即Windows可执行文件)文件格式,并且本身包含的就是二进制代码,但是不一定能执行,因为并不能保证其中一定有main函数。当编译器将一个工程里的所有.cpp文件以分离的方式编译完毕后,再由链接器进行链接成为一个.exe或.dll文件

编译过程

目标文件:

编译后生成的文件,以机器码的形式包含了编译单元里所有的函数和数据、导出符号表、未解决符号表、地址重定向表
导出符号表:即该目标文件可以提供的符号及地址。
未解决符号表:即找不到地址的符号的列表,告诉链接器这些符号没找到地址。
地址重定向表:链接的时候,链接器会为目标文件的“未解决符号表”里的符号在其他目标文件中寻找地址,但是每个目标文件的地址都是从0x0000开始的,这样直接将对方文件中符号的地址拿过来用显然会是不正确的,为了区分不同的文件,链接器在链接时就会对每个目标文件的地址进行调整。这样就可以保证地址不会重复。因为被加上了起始地址,所以符号在自身文件中的实际地址就不对了,需要再用一张地址重定向表记录符号相对自身文件的地址。

目标文件的类型:

可重定位文件(.o、.obj文件):其中包含有适合于其它目标文件链接来创建一个可执行的或者共享的目标文件的代码和数据。每个cpp会被编译成一个.o文件
共享的目标文件(库文件):这种文件存放了适合于在两种上下文里链接的代码和数据。
第一种是链接程序(静态库)可把它与其它可重定位文件及共享的目标文件一起处理来创建另一个目标文件静态链接库实际上是一个目标文件的集合,其中的每个文件含有库中的一个或 者一组相关函数的代码
第二种是动态链接程序(动态库)将它与另一个可执行文件及其它的共享目标文件结合到一起,创建一个进程映象动态链接库在程序执行时才被调用
可执行文件 一个可以被操作系统创建一个进程来执行之的文件

.o文件在编译后就能获得,但是库文件、可执行文件都需要在链接后才能获得

编译过程

1.编译预处理: 读取源程序,对其中的伪指令(以#开头的指令)和特殊符号进行处理。
(1)宏定义指令,如# define Name TokenString,#undef等
(2)条件编译指令,如#ifdef,#ifndef,#else,#elif,#endif,等等。
(3)头文件包含指令,如#include "FileName"或者#include <FileName>等。
(4)特殊符号,预编译程序可以识别一些特殊的符号。

2.编译,优化阶段:经过预编译得到的输出文件中,将只有常量。如数字、字符串、变量的定义,以及关键字,如main,if,else,for,while,{,},+,-,*,\,等等。预编译程序所要作得工作就是通过词法分析和语法分析,在确认所有的指令都符合语法规则之后,将其翻译成等价的中间代码表示或汇编代码。 优化一部分是对中间代码的优化。这种优化不依赖于具体的计算机。另一种优化则主要针对目标代码的生成而进行的。

3.汇编过程:汇编过程实际上指把汇编语言代码翻译成目标机器指令的过程。生成目标文件(.o文件、.obj文件)。

链接过程

链接:链接程序的主要工作就是将有关的目标文件(库文件、.o文件)彼此相连接,也即将在一个文件中引用的符号同该符号在另外一个文件中的定义连接起来,使得所有的这些目标文件成为一个能够被操作系统装入执行的统一整体。
具体工作: 当链接器进行链接的时候,首先决定各个目标文件在最终可执行文件里的位置。然后访问所有目标文件的地址重定义表,对其中记录的地址进行重定向(加上一个偏移量,即该编译单元在可执行文件上的起始地址)。然后遍历所有目标文件的未解决符号表,并且在所有的导出符号表里查找匹配的符号,并在未解决符号表中所记录的位置上填写实现地址。最后把所有的目标文件的内容写在各自的位置上,再作一些另的工作,就生成一个可执行文件。

链接方式

静态链接函数的代码将从其所在地静态链接库中被拷贝到最终的可执行程序中。这样该程序在被执行时这些代码将被装入到该进程的虚拟地址空间中
动态链接:函数的代码被放到称作是动态链接库或共享对象的某个目标文件中。链接程序此时所作的只是在最终的可执行程序中记录下共享对象的名字以及其它少量的登记信息。在此可执行文件被执行时,动态链接库的全部内容将被映射到运行时相应进程的虚地址空间。动态链接程序将根据可执行程序中记录的信息找到相应的函数代码。

编译过程

C/C++中提供的一些特性

extern:这就是告诉编译器,这个变量或函数在别的编译单元里定义了,也就是要把这个符号放到未解决符号表里面去(外部链接)。
默认链接属性:对于函数和变量,默认链接是外部链接,对于const变量,默认内部链接
外部链接的利弊:外部链接的符号在整个程序范围内都是可以使用的,这就要求其他编译单元不能导出相同的符号(不然就会报 duplicated external symbols)。

头文件里一般只可以有声明不能有定义:头文件可以被多个编译单元包含,如果头文件里面有定义的话,那么每个包含这头文件的编译单元都会对同一个符号进行定义,如果该符号为外部链接,则会导致duplicated external symbols链接错误。
头文件中的inline 函数可以被多个cpp包含而不造成符号冲突:因为它会被直接嵌入到调用的地方,内部联结不形成外部符号,对外不可见。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

c++程序编译过程及相关概念 的相关文章

随机推荐

  • mavlink解析

    之前看了mavlink协议 xff0c 网上关于mavlink的资料不多 本系列共三篇 xff0c 这是第一篇 本文大概总结了下对mavlink协议的理解 以下如不说明都是说mavlink v1 0版本 首先附上mavlink的各个消息的简
  • Tomcat部署及优化

    目录 1 Tomcat概述 1 Tomcat的概念 2 Tomcat的核心组件 3 Java Servlet 的概念 4 JSP的概念 5 Tomcat中最顶层的容器 server 6 四个子容器的作用 7 Tomcat请求过程 2 Tom
  • STC89C52系列单片机内部资源——串口通信

    计算机通信是将计算机技术和通信技术的相结合 xff0c 完成计算机与外部设备或计算机与计算机之间的信息交换 可以分为两大类 xff1a 并行通信与串行通信 并行通信通常是将数据字节的各位用多条数据线同时进行传送 并行通信控制简单 传输速度快
  • 用TCP/UDP 网络调试助手(PC版)无法获取网页信息

    以前的网页均是http开头的 xff0c 是没有加密的 xff0c 以前用GET就能获取网页的信息 xff0c 但是现在的基本是https开头的 xff0c 是加密的 xff0c 所以现在用以前的方法 xff0c 只能返回301错误 现在想
  • Ubuntu 20.04安装Ros Noetic及Ubuntu 18.04安装ROS Melodic(两版本详细填坑)

    Ubuntu 20 04安装Ros Noetic及18 04安装ROS Melodic 表1 1 ROS的历史版本 1 设置安装源2 添加秘钥3 更新列表4 开始安装5 配置ROS环境变量6 安装rosinstall6 1 初始化核心组件r
  • linux 根文件系统,根设备,sys_open, sys_read, sys_write, sys_mount, sys_mknod

    笔者语 xff1a 1 内容涉及比较多 xff0c 自己也没有分章节 xff0c 因为觉得这些内容关联性很强 xff0c 自己也懒的去弄了 2 本文涉及以下内容 xff1a 2 1 内核启动过程中 xff0c 第一个文件系统为rootfs
  • uboot的配置(make xxx_config)和编译(make)工程解读

    uboot编译三步走 make xxx configmakemake install 第一步make xxx config 这一步是产生板子的配置文件 我们假设是配置ast2500evb板子 xff0c 那么这里的配置命令就是 make a
  • uboot启动之第一次运行C函数到uboot重定位

    接上一篇博文 uboot启动流程之上电启动到第一次准备好C语言运行环境 xff0c 本文从board init f 开始 board init f定义在uboot common board f c中 CONFIG SYS GENERIC B
  • pci总线扫描及pci网卡驱动

    本文讲述的基于intel 总线架构的硬件架构为例来说明linux是如何扫描总线上的PCI设备 CPU通过前端总线FS连接到北桥芯片North Bridge Chip 又称host Bridge 北桥芯片本身也是PCI总线0上的PCI设备 北
  • k8s下POD之间的通信过程

    本文主要描述同一个node之内的pod之间的通信 xff0c 以及不同node之间的pod之间的通信 同一个 node 上的不同 pod 之间的通信 xff1a 假设上图的POD A要和POD B 通信 POD A 发送一个包 xff0c
  • bash: ./<one_executable_file>: no such file or directory

    关于这个问题 xff0c 原因很多 但大部分的资料都是说PATH环境变量坏掉了 xff0c 或者 etc profile坏掉了 但其实 xff0c 还有一种原因 xff0c 就是你的可执行程序 lt one executable file
  • linux下动态库so的debug方式

    1 查看哪些进程使用了特定的动态库so lsof lib arm linux gnueabi libselinux so 1 COMMAND PID USER FD TYPE DEVICE SIZE OFF NODE NAME init 1
  • linux usb gadget driver代码

    本文基于linux 5 4 124 aspeed 2600 BMC 的代码实现来描述arm结构下的gadget driver 在读之前 xff0c 我们需要了解什么是usb gadget driver xff0c 以及它的作用 从英文字面上
  • 【毕业设计】深度学习社交安全距离检测系统 - python opencv

    文章目录 0 前言1 课题背景2 实现效果3 相关技术3 1 YOLOV43 2 基于 DeepSort 算法的行人跟踪 4 最后 0 前言 x1f525 Hi xff0c 大家好 xff0c 这里是丹成学长的毕设系列文章 xff01 x1
  • 关于进程和线程对于全局变量共享的问题学习总结

    进程和线程的共享 本文档可以说明以下几个问题 xff1a 问题一 xff1a 多进程编程中 xff0c 不同进程是否可以通过全局变量来通信 问题二 xff1a 多线程编程中 xff0c 不同线程是否可以通过全局变量来通信 xff1f 在说明
  • C语言调用so动态库的两种方式

    方式1 xff1a 类似静态库的调用 xff08 使用头文件 xff09 这种方式生成的程序会在启动时候就加载so动态库 add h span class hljs keyword int span add span class hljs
  • GPS RTK测量定位原理

    转自 xff1a https baijiahao baidu com s id 61 1603136753092877848 amp wfr 61 spider amp for 61 pc 手机定位是什么原理 xff1f 实时动态工程测量是
  • STM32学习笔记 - 串口的初始设置

    STM32学习笔记 串口的初始设置 1 声明结构体变量 GPIO InitTypeDef GPIO InitStructure GPIO InitTypeDef是一个结构体变量 xff0c 包括GPIO Pin xff08 u16类型 xf
  • STL 容器区别:vector、list、deque、set、map的底层实现

    文章转自 xff1a http blog csdn net lmh12506 article details 8445025 1 set和map 比较 setmap共同点都是无序的保存元素 xff0c 只是通过它提供的借口对里面的元素进行访
  • c++程序编译过程及相关概念

    编译 把源文件中的源代码翻译成机器语言 xff0c 保存到目标文件中 如果编译通过 xff0c 就会把CPP转换成OBJ文件 编译单元 xff1a 每个cpp就是一个编译单元 xff0c 每个编译单元相互之间是独立且相互不知的 一个编译单元