C++的编译过程详解

2023-05-16

C/C++编译过程

C/C++编译过程主要分为4个过程

  1. 编译预处理
  2. 编译、优化阶段
  3. 汇编过程
  4. 链接程序

一、编译预处理

(1)宏定义指令,如#define Name TokenString,#undef等。 对于前一个伪指令,预编译所要做的是将程序中的所有Name用TokenString替换,

但作为字符串常量的 Name则不被替换。对于后者,则将取消对某个宏的定义,使以后该串的出现不再被替换。

(2)条件编译指令,如#ifdef,#ifndef,#else,#elif,#endif等。 这些伪指令的引入使得程序员可以通过定义不同的宏来决定编译程序对哪些代码进行处理。

预编译程序将根据有关的文件,将那些不必要的代码过滤掉

(3) 头文件包含指令,如#include "FileName"或者#include 等。 在头文件中一般用伪指令#define定义了大量的宏(最常见的是字符常量),

同时包含有各种外部符号的声明。 包含到c源程序中的头文件可以是系统提供的,这些头文件一般被放在/usr/include目录下。

在程序中#include它们要使用尖括号(< >)。

另外开发人员也可以定义自己的头文件,这些文件一般与c源程序放在同一目录下,此时在#include中要用双引号("")。

(4)特殊符号,预编译程序可以识别一些特殊的符号。 例如在源程序中出现的#line标识将被解释为当前行号(十进制数),
上面程序实现了对宏line的运用

(5)预处理模块 预处理工作由#pragma命令完成,#Pragma命令将设定编译器的状态或者是指示编译器完成一些特定的动作。

#pragma指令对每个编译器给出了一个方法,在保持与C和C++语言完全兼容的情况下,给出主机或操作系统专有的特征。

依据定义,编译指示是机器或操作系统专有的,且对于每个编译器都是不同的。
打开C标准库函数,如stdio.h,我们总能找到下面这一句指示编译器初始化堆栈
#include “iostream”
#line 100
using namespace std;
int main(int argc, char* argv[])
{
cout<<“LINE:”<<LINE<<endl;
return 0;
}
/*--------------------

  • 输出结果为:
  • LINE:103
  • 本来输出的结果应该是 7,但是用#line指定行号之后,使下一行的行号变为,
  • 到输出语句恰为行103
    ---------------------*/
    C/C++编译过程
    或者程序指示编译器去链接系统动态链接库或用户自定义链接库

二、编译、优化阶段

经过预编译得到的输出文件中,只有常量;如数字、字符串、变量的定义,以及C语言的关键字,如main,if,else,for,while,{,}, +,-,*,\等等。
在《编译原理》中我们可以了解到一个编译器对程序代码的编译主要分为下面几个过程:
a) 词法分析
b) 语法分析
c) 语义分析
d) 中间代码生成
e) 代码优化
f) 代码生成
g) 符号表管理
h) 将多个步骤组合成趟
i) 编译器构造工具
在这里我们主要强调对函数压栈方式(函数调用约定)的编译处理
C与C++语言调用方式大体相同,下面是几种常用的调用方式:

__cdecl 是C DECLaration的缩写(declaration,声明),表示C语言默认的函数调用方法:所有参数从右到左依次入栈,

这些参数由调用者清除,称为手动清栈。被调用函数不需要求调用者传递多少参数,调用者传递过多或者过少的参数,

甚至完全不同的参数都不会产生编译阶段的错误。

_stdcall 是StandardCall的缩写,是C++的标准调用方式:所有参数从右到左依次入栈,如果是调用类成员的话,

最后一个入栈的是this指针。这些堆栈中的参数由被调用的函数在返回后清除,使用的指令是 retnX,X表示参数占用的字节数,

CPU在ret之后自动弹出X个字节的堆栈空间。称为自动清栈。函数在编译的时候就必须确定参数个数,

并且调用者必须严格的控制参数的生成,不能多,不能少,否则返回后会出错。

PASCAL 是Pascal语言的函数调用方式,在早期的c/c++语言中使用这种调用方式,

参数压栈顺序与前两者相反,但现在我们在程序中见到的都是它的演化版本,其实
#pragma comment(lib,_T(“GDI32.lib”))
#ifdef _MSC_VER
/*

  • Currently, all MS C compilers for Win32 platforms default to 8 byte
  • alignment.
    /
    #pragma pack(push,_CRT_PACKING)
    #endif /
    _MSC_VER */
    C/C++编译过程
    质是另一种调用方式
    _fastcall是编译器指定的快速调用方式。由于大多数的函数参数个数很少,使用堆栈传递比较费时。因此_fastcall通常规定将前两个(或若干个)参数由寄存器传递,其余参数还是通过堆栈传递。不同编译器编译的程序规定的寄存器不同。返回方式和_stdcall相当。
    _thiscall 是为了解决类成员调用中this指针传递而规定的。_thiscall要求把this指针放在特定寄存器中,该寄存器由编译器决定。VC使用ecx,Borland的C++编译器使用eax。返回方式和_stdcall相当。
    _fastcall 和 _thiscall涉及的寄存器由编译器决定,因此不能用作跨编译器的接口。所以Windows上的COM对象接口都定义为_stdcall调用方式。
    C中不加说明默认函数为_cdecl方式(C中也只能用这种方式),C++也一样,但是默认的调用方式可以在IDE环境中设置。简单的我们可以从printf函数看出
    printf使用从从左至右压栈,返回int型并由_CRTIMP指定封在动态链接库中。
    通过金典的hello world程序我们可以知道编译器对其argc和argv[]这两个参数进行了压栈,并且argc留在了栈顶
    优化处理是编译系统中一项比较艰深的技术。它涉及到的问题不仅同编译技术本身有关,而且同机器的硬件环境也有很大的关系。优化处理主要分为下面几个过程:
  1. 局部优化
    a) 基本块的划分
    b) 基本块的变换
    c) 基本块的DAG表示
    d) DAG的应用
    e) 构造算法讨论
  2. 控制流分析和循环优化
    a) 程序流图与循环
    /金典的hello world/
    #include <stdio.h>
    int main(int argc, char* argv[])
    {
    printf(“hello world”);
    return 0;
    }
    Check_return_opt _CRTIMP int __cdecl printf(In_z Printf_format_string const char * _Format, …);
    #define CALLBACK _stdcall /* Windows程序回调函数*/
    #define WINAPI _stdcall
    #define WINAPIV _cdecl
    #define PASCAL _stdcall /在c++语言中使用了StandardCall调用方式/
    #define PASCAL _cdecl/在c语言中使用了C DECLaration调用方式/
    C/C++编译过程
    b) 循环
    c) 循环的查找
    d) 可归约流图
    e) 循环优化
  3. 数据流的分析与全局优化
    a) 一些主要的概念
    b) 数据流方程的一般形式
    c) 到达一定值数据流方程
    d) 可用表达式及其数据流方程
    e) 活跃变量数据流方程
    f) 复写传播
    经过优化得到的汇编代码必须经过汇编程序的汇编转换成相应的机器指令,方可能被机器执行。

三、汇编过程

汇编过程实际上指把汇编语言代码翻译成目标机器指令的过程。对于被翻译系统处理的每一个C语言源程序,

都将最终经过这一处理而得到相应的目标文件。目标文件中所存放的也就是与源程序等效的目标的机器语言代码。

目标文件由段组成。通常一个目标文件中至少有两个段: 代码段:该段中所包含的主要是程序的指令。

该段一般是可读和可执行的,但一般却不可写。 数据段:主要存放程序中要用到的各种全局变量或静态的数据。一般数据段都是可读,可写,可执行的。

四、链接程序

由汇编程序生成的目标文件并不能立即就被执行,其中可能还有许多没有解决的问题。

例如,某个源文件中的函数可能引用了另一个源文件中定义的某个符号(如变量或者函数调用等);

在程序中可能调用了某个库文件中的函数,等等。所有的这些问题,都需要经链接程序的处理方能得以解决。

链接程序的主要工作就是将有关的目标文件彼此相连接,也即将在一个文件中引用的符号同该符号在另外一个文件中的定义连接起来,

使得所有的这些目标文件成为一个能够诶操作系统装入执行的统一整体。

根据开发人员指定的同库函数的链接方式的不同,链接处理可分为两种:

(1)静态链接 在这种链接方式下,函数的代码将从其所在地静态链接库中被拷贝到最终的可执行程序中。

这样该程序在被执行时这些代码将被装入到该进程的虚拟地址空间中。静态链接库实际上是一个目标文件的集合,

其中的每个文件含有库中的一个或者一组相关函数的代码。

(2) 动态链接
在此种方式下,函数的代码被放到称作是动态链接库或共享对象的某个目标文件中。
链接程序此时所作的只是在最终的可执行程序中记录下共享对象的名字以及其它少量
的登记信息。在此可执行文件被执行时,动态链接库的全部内容将被映射到运行时相应
进程的虚地址空间。动态链接程序将根据可执行程序中记录的信息找到相应的函数代码。
C/C++编译过程
对于可执行文件中的函数调用,可分别采用动态链接或静态链接的方法。使用动
态链接能够使最终的可执行文件比较短小,并且当共享对象被多个进程使用时能节约一
些内存,因为在内存中只需要保存一份此共享对象的代码。但并不是使用动态链接就一

定比使用静态链接要优越。在某些情况下动态链接可能带来一些性能上损害。

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

C++的编译过程详解 的相关文章

  • 相机内参标定,相机和激光雷达联合标定

    相机内参标定 xff0c 相机和激光雷达联合标定 一 相机标定原理1 1 成像过程1 2 标定详解 二 相机和激光雷达联合标定2 1 标定方法汇总2 2 Autoware的安装与运行2 2 1 安装方式2 2 2 安装Autoware的依赖
  • Ubuntu20.04安装和编译运行lidar_align来联合标定lidar与imu的外参

    Ubuntu20 04安装和编译运行lidar align来联合标定lidar与imu的外参 一 编译运行lidar align1 1 下载地址1 2 编译1 2 1 nlopt问题解决1 2 2 c 43 43 问题解决 二 处理数据集三
  • ROS小工具学习与使用

    ROS小工具学习与使用 rqt的使用 rqt bag工具 rqt bag span class token operator lt span your bagfile span class token operator gt span sp
  • printf函数的实现方法

    printf是一个C库函数 xff0c 用于向标准输出 xff08 stdout xff09 写入格式化的字符串 如果格式字符串包含格式说明符 xff08 以 开头的子序列 xff09 xff0c 则需要额外的参数来替换相应的说明符 实现p
  • linux下查看cmake的版本

    方法 在命令行输入指令 xff1a cmake span class token operator span version
  • C++常用标准库

    STL是Standard Template Library的简称 xff0c 中文名标准模板库 从根本上说 xff0c STL是一些 容器 的集合 xff0c 这些 容器 有list vector set map等 xff0c STL也是算
  • 如何轻松写出正确的链表代码

    如何轻松写出正确的链表代码 xff1f 1 理解指针或引用的含义 将某个变量赋值给指针 xff0c 实际上就是将这个变量的地址赋值给指针 xff0c 或者反过来说 xff0c 指针中存储了这个变量的内存地址 xff0c 指向了这个变量 xf
  • JVM之虚拟机栈详细讲解

    Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域 这些区域有各自的用途 xff0c 以及创建和销毁的时间 xff0c 有的区域随着虚拟机进程的启动而一直存在 xff0c 有些区域则是依赖用户线程的启动和结
  • 【图像处理】特征点算法整理总结

    特征点检测 1 Susan SUSA xff08 Smallest Univalue Segment Assimilating Nucleus xff09 算子是一种高效的边缘和角点检测算子 xff0c 并且具有结构保留的降噪功能 原理 用
  • 图像特征点匹配算法

    sift https blog csdn net weixin 38404120 article details 73740612 https blog csdn net abcjennifer article details 763968
  • 算法目标检测面经

    1 自我介绍 2 简历上的项目 网易雷火 AI研究员 1 ResNet FCN Fasterrcnn 2 膨胀腐蚀的原理 3 均值滤波的原理 时间复杂度 怎么优化 4 第k大的数 topK个数 网易互娱预研 深度学习计算机视觉 1 语义分割
  • 图像配准(Image Registration)简介

    图像配准在目标检测 模型重建 运动估计 特征匹配 xff0c 肿瘤检测 病变定位 血管造影 地质勘探 航空侦察等领域都有广泛的应用 每一种配准方法通常都针对某个具体问题而设计的 xff0c 众多方法中 xff0c 唯一的共性就是每个配准问题
  • SSD算法详解

    转载 xff1a https blog csdn net ytusdc article details 86577939 SSD github https github com weiliu89 caffe tree ssd SSD pap
  • 深度学习-目标检测评估指标P-R曲线、AP、mAP

    基本概念 P R曲线中 xff0c P为图中precision xff0c 即精准度 xff0c R为图中recall xff0c 即召回率 Example 下面通过具体例子说明 首先用训练好的模型得到所有测试样本的confidence s
  • 使用gitlab初次上传代码

    提要 项目开发中需要使用gitlab来管理代码 xff0c 将自己开发的模块上传到gitlab 第一次使用这个代码管理仓库 xff0c 记录一下 方法 1 首先注册gitlab的账号 这个在百度上搜一下gitlab的官网 xff0c 进去后
  • Keil5添加.c文件与.h文件的方法-导入支持库-新大陆物联网竞赛-Lora模块&NBIOT模块例程-添加导入文件

    一 概述 在某些情况下 xff0c 我们使用现用的物联网开发例程 xff0c 例如新大陆物联网的Lora与NBIOT的例程 xff0c 我们对其例程内目前所有的库不满意 xff0c 不足以实现开发需要的功能 xff0c 我们需要在原有工程上
  • 初探DSO-SLAM并运行dso_ros

    最近在做SLAM相关的工作 xff0c 用思岚的A2激光雷达在turtlebot3上测试SLAM建图效果 xff0c 感觉还是不错的 由于项目在方案上还没有确定选择哪种作为SLAM的最终方案 xff0c 在我测试奥比中光ASTRA mini
  • 虚拟机中安装CMake工具

    https www cnblogs com yanqingyang p 12731855 html
  • 寻路系统:动态障碍物

    寻路的相关参数 需要先勾选 游戏场景中所有需要烘焙路径信息的游戏对象状态为 static 然后点开windos菜单下的navigation窗口进行烘培 Navigation Static xff1b 表示该游戏对象是否参与导航网格的烘培 G
  • Ubuntu18.04下使用cmake编译一个OpenCV程序(编写CMakeLists.txt文件)

    导航 1 安装OpenCV1 1首先安装OpenCV 1 2定位OpenCV 2 创建一个项目3 编写一个基础OpenCV程序4 编写CMakeLists txt文件 为了记录以及防止遗忘 xff0c 备份一个大致能满足运行的CMakeLi

随机推荐

  • linux下最全curl命令使用方式学习和拓展

    为什么要使用curl命令 xff1f curl命令可以帮助我们在linux服务内部通讯 xff0c 排查接口是否能够正确调用 xff0c 外网的接口是否有防火墙限制 xff0c 内网的请求可以快速帮我们获取接口参数返回 xff0c 并且调试
  • 【传感器标定】kalibr 标定工具箱问题汇总

    文章目录 写在前面一 运行一段时间报错 96 Spline Coefficient Buffer Exceeded Set larger buffer margins 96 的解决方法1 问题描述2 解决方法参考链接 写在前面 kalibr
  • C++中的Vector存放指针的清空问题

    C 43 43 中的Vector存放指针的清空问题 一 写在前面二 参考做法参考链接 这两个链接写得挺好 xff0c 可以参考下 一 写在前面 C 43 43 很难的一个重要原因就是内存管理的问题 xff0c 因为你既要管理申请内存 xff
  • find_package(xxxx REQUIRED)找不到路径的全平台通用解决办法

    相信刚学cmake c 43 43 的朋友们在编译的时候一定被这个问题折磨许久哈 然后怎么搜怎么添加都有问题 xff0c 仔细研究了我才发现这个地方不同的索引机制 xff0c 但是表面上都是 find package xxxx REQUIR
  • STC51-串口通信

    1 并行与串行基本通信方式 随着单片机系统的广泛应用和计算机网络技术的普及 xff0c 单片机的通信功能愈来愈显得重要 单片机通信是指单片机与计算机或单片机与单片机之间的信息交换 xff0c 通常单片机与计算机之间的通信我们用的较多 通信有
  • qt种实现搜索栏功能

    引言 在搜索栏种输入要搜索的文本 xff0c 就会出现相关联的文本提示 xff0c 这是可以通过鼠标选中要搜索的文本 xff0c 或者通过上下键选中要搜索的文本 效果 效果图如下所示 xff1a 实现 下面是相关的代码实现 xff0c 读者
  • orangePi3 TLS烧录启动、wifi配置和ssh登录、烧录进内置emmc flash

    orangePi3 TLS烧录启动 wifi配置和ssh登录 烧录进内置emmc flash 烧录镜像到TF卡启动 镜像下载 官方镜像地址 xff1a http www orangepi cn html hardWare computerA
  • C/C++——代码的编译和运行

    1 编译过程 每种高级语言都有对应的编译器 xff0c 而且针对不同指令集架构的CPU会提供不同的编译器 本文以C语言为例 xff0c CPU指令集架构不做前提约束 xff0c 实际上同一种语言也只有在狭义的编译阶段有所区别 xff0c 其
  • Arduino UNO GPS 制作 里程表 经纬度

    机缘 上过月买了一个GPS模块 xff0c 然后我用esp32读取GPS数据 xff0c 并使用LVGL显示GPS信息 期间踩了很多坑 xff0c 我用乐鑫的IDF开发 xff0c 自己写了一个GPS信息提取方法 xff0c BUG很多 x
  • socket编程——UDP协议(C语言编程)

    1 收发信息 ssize t sendto int socket void message size t length int flags struct sockaddr dest addr socklen t dest len 返回值 l
  • 【C语言之线性表链式存储结构】

    C语言之线性表链式存储结构 文章目录 C语言之线性表链式存储结构前言一 线性表链式存储结构定义二 相关概念1 结点1 头指针 三 代码描述1 单链表结点定义1 单链表的创建2 单链表的查找3 在单链表中 xff0c 替换某一个位置的数据4
  • unsigned char* (uchar*) 转为QImage

    场景 xff1a 有一副图像 xff0c 事先已经因为各种需要被读取到了内存中 xff0c 且不可再根据路径读取 xff0c 只能读取内存中的数据转为QImage 百度过好久 xff0c 没有一个帖子说的特别详细 xff0c 解释的特别清楚
  • 卷积的含义-详解

    原文链接 xff1a 点击此处看知乎原文 最近需要用到卷积对图像进行处理 xff0c 不明白卷积的含义 xff0c 找资料的时候在知乎找到一个很优秀的评论 xff0c 特此记录一下 以下内容来自于原文复制 xff1a 对卷积的困惑 卷积这个
  • 图像处理-直方图均衡化(C++实现,不依赖opencv)

    近来接触图像处理领域 xff0c opencv入门之后 xff0c 想自己动手实现一些算法 xff0c 先从直方图均衡化开始吧 xff01 我使用的图像文件是只包含数据yuv格式图像 xff0c 以后等需要的时候再处理从普通格式 xff08
  • 图像处理-Sobel边缘检测(C++实现,不依赖opencv)

    边缘检测一直是图像处理中比较热门的一块 xff0c 今天简单实现了下sobel算法 先上图 xff1a 原图 xff1a Sobel处理 彩图 xff1a Sobel处理 灰度图 xff1a 可以看到在不复杂的情况下 xff0c Sobel
  • 图像处理-高斯滤波和升级版Side Window版高斯滤波(C++实现,无需opencv)

    图像处理绕不开的一个环节就是去燥 xff0c 去掉各式各样的噪声来保证图像的质量 今天将高斯滤波实现了下 xff0c 在此稍作记录 以往惯例 xff0c 先上图 xff1a 原图 xff1a 高斯滤波 xff1a Side Window版高
  • Linux下,使用nginx+ffmpeg+video.js实现直播效果(含centos7环境配置步骤)

    前言 近来因为项目需要 xff0c 需要做一个把视频解码然后推流 xff0c 在浏览器播放的功能 然后查资料 找demo xff0c 最终决定使用FFmpeg 43 nginx来完成相应功能 xff0c 过程颇为心酸 xff0c 在此做下笔
  • 使用QMap保存数据时,若出现相同的键,可以在不改变原有的变量存储选型基础上,使用insertMulti函数来解决

    场景 问题发生场景解决办法方案一方案二方案三 xff08 重点 xff09 针对方案三的示例 问题发生场景 本来项目中选型选择的是QMap来存储相应的键值对 xff0c 根据Map中的键的顺序取出对应的值 但是在使用的过程中 xff0c 发
  • C语言,声明和实现放在头文件中

    将头文件和实现放在同一个文件中 普通函数与静态函数是有区别的 静态函数 xff1a static h ifndef CRND INCLUDE CRND H define CRND INCLUDE CRND H static int pore
  • C++的编译过程详解

    C C 43 43 编译过程 C C 43 43 编译过程主要分为4个过程 编译预处理编译 优化阶段汇编过程链接程序 一 编译预处理 xff08 1 xff09 宏定义指令 xff0c 如 define Name TokenString x