C++程序编译过程

news/2024/6/17 14:33:51 标签: c++, c语言

C++程序编译过程

  • 1.编译流程图
  • 2.预处理
  • 3.编译
  • 4.汇编
  • 5.链接

1.编译流程图

C++程序编译过程

2.预处理

编译器将C程序的头文件编译进来,还有宏的替换,可以用gcc的参数-E来参看。

主要处理源代码文件中的以“#”开头的预编译指令。处理规则见下

1、删除所有的#define,展开所有的宏定义。

2、处理所有的条件预编译指令,如“#if”、“#endif”、“#ifdef”、“#elif”和“#else”。

3、处理“#include”预编译指令,将文件内容替换到它的位置,这个过程是递归进行的,文件中包含其他文件。

4、删除所有的注释,“//”和“/**/”。

5、保留所有的#pragma 编译器指令,编译器需要用到他们,如:#pragma once 是为了防止有文件被重复引用。

6、添加行号和文件标识,便于编译时编译器产生调试用的行号信息,和编译时产生编译错误或警告是能够显示行号。

命令:unix>gcc –o hello hello.c
作用:将hello.c预处理输出hello.i

3.编译

这个阶段编译器主要做词法分析、语法分析、语义分析等,在检查无错误后后,把代码翻译成汇编语言[2]。可用gcc的参数-S来参看。
编译器(ccl)将文本文件hello.i 翻译成文本文件hello.s, 它包含一个汇编语言程序。
一条低级机器语言指令。

把预编译之后生成的xxx.i或xxx.ii文件,进行一系列词法分析、语法分析、语义分析及优化后,生成相应的汇编代码文件。

1、词法分析:利用类似于“有限状态机”的算法,将源代码程序输入到扫描机中,将其中的字符序列分割成一系列的记号。

2、语法分析:语法分析器对由扫描器产生的记号,进行语法分析,产生语法树。由语法分析器输出的语法树是一种以表达式为节点的树。

3、语义分析:语法分析器只是完成了对表达式语法层面的分析,语义分析器则对表达式是否有意义进行判断,其分析的语义是静态语义——在编译期能分期的语义,相对应的动态语义是在运行期才能确定的语义。

4、优化:源代码级别的一个优化过程。

5、目标代码生成:由代码生成器将中间代码转换成目标机器代码,生成一系列的代码序列——汇编语言表示。

6、目标代码优化:目标代码优化器对上述的目标机器代码进行优化:寻找合适的寻址方式、使用位移来替代乘法运算、删除多余的指令等。

命令:gcc -S hello.i -o hello.s
作用:将预处理输出文件hello.i汇编成hello.s文件

4.汇编

汇编器as 将hello.s 翻译成机器语言保存在hello.o 中(二进制文本形式)。

将汇编代码转变成机器可以执行的指令(机器码文件)。只是根据汇编指令和机器指令的对照表一一翻译过来,汇编过程有汇编器AS完成。经汇编之后,产生目标文件(与可执行文件格式几乎一样)xxx.o(Windows下)、xxx.obj(Linux下)。

5.链接

printf函数存在于一个名为printf.o的单独预编译目标文件中。必须得将其并入到hello.o的程序中,链接器就是负责处理这两个的并入,结果得到hello文件,它就是一个可执行的目标文件。

将不同的源文件产生的目标文件进行链接,从而形成一个可以执行的程序。链接分为静态链接和动态链接:

1、静态链接:

函数和数据被编译进一个二进制文件。在使用静态库的情况下,在编译链接可执行文件时,链接器从库中复制这些函数和数据并把它们和应用程序的其它模块组合起来创建最终的可执行文件。

空间浪费:因为每个可执行程序中对所有需要的目标文件都要有一份副本,所以如果多个程序对同一个目标文件都有依赖,会出现同一个目标文件都在内存存在多个副本;

更新困难:每当库函数的代码修改了,这个时候就需要重新进行编译链接形成可执行程序。

运行速度快:但是静态链接的优点就是,在可执行程序中已经具备了所有执行程序所需要的任何东西,在执行的时候运行速度快。

2、动态链接:

动态链接的基本思想是把程序按照模块拆分成各个相对独立部分,在程序运行时才将它们链接在一起形成一个完整的程序,而不是像静态链接一样把所有程序模块都链接成一个单独的可执行文件。

共享库:就是即使需要每个程序都依赖同一个库,但是该库不会像静态链接那样在内存中存在多分,副本,而是这多个程序在执行时共享同一份副本;

更新方便:更新时只需要替换原来的目标文件,而无需将所有的程序再重新链接一遍。当程序下一次运行时,新版本的目标文件会被自动加载到内存并且链接起来,程序就完成了升级的目标。

性能损耗:因为把链接推迟到了程序运行时,所以每次执行程序都需要进行链接,所以性能会有一定损失。


http://www.niftyadmin.cn/n/1371572.html

相关文章

C++多态、虚函数、虚函数表、编译期、运行期、静态、动态的理解

关于C多态1. 多态分为静态多态和动态多态1.1 静态多态1.1.1函数重载1.1.2模板1.1.3静态多态总结1.2 动态多态:在运行时期才能决定函数行为1.2.1先讲一些储备知识,不然初学者听着迷糊1.2.2 多态的体现:1.2.3 动态的体现1. 多态分为静态多态和动…

面试题 节流理解以及实现节流

类似王者荣耀的技能&#xff0c;冷却事件为5s在这5秒中咋点都不会放技能&#xff0c;当五秒过了才能放技能 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content…

LeetCode-132. 分割回文串 II

LeetCode-132. 分割回文串 II 难度&#xff1a;困难 给你一个字符串 s&#xff0c;请你将 s 分割成一些子串&#xff0c;使每个子串都是回文。 返回符合要求的 最少分割次数 。 示例 &#xff1a; 输入&#xff1a;s “aab” 输出&#xff1a;1 解释&#xff1a;只需一次分…

面试题 css清除浮动的方法

浮动的产生 1、普通流定位 static&#xff08;默认方式&#xff09; 普通流定位&#xff0c;又称为文档流定位&#xff0c;是页面元素的默认定位方式 页面中的块级元素&#xff1a;按照从上到下的方式逐个排列 页面中的行内元素&#xff1a;按照从左到右的方式逐个排列 但是如何…

LeetCode-516. 最长回文子序列

LeetCode-516. 最长回文子序列 给你一个字符串 s &#xff0c;找出其中最长的回文子序列&#xff0c;并返回该序列的长度。 子序列定义为&#xff1a;不改变剩余字符顺序的情况下&#xff0c;删除某些字符或者不删除任何字符形成的一个序列。 示例 1&#xff1a; 输入&#…

面试题 说一说px em rem的区别

px px单位的名称为像素&#xff0c;它是一个固定大小的单元&#xff0c;像素的计算是针对&#xff08;电脑/手机&#xff09;屏幕的&#xff0c;一个像素&#xff08;1px&#xff09;就是&#xff08;电脑/手机&#xff09;屏幕上的一个点&#xff0c;即屏幕分辨率的最小分割。…

面试题 vue生命周期

beforecreate这时还不能访问data数据和methods方法&#xff0c;初始化生命周期&#xff0c;事件但是数据代理还没有开始 beforecreate之后开始初始化数据代理和数据检测 在进入create生命周期之后就可以访问data中的数据和mothods中的方法 进入beforemount接开始生成虚拟DOM mo…

LeetCode-1143. 最长公共子序列

LeetCode-1143. 最长公共子序列 难度&#xff1a;中等 给定两个字符串 text1 和 text2&#xff0c;返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 &#xff0c;返回 0 。 一个字符串的 子序列 是指这样一个新的字符串&#xff1a;它是由原字符串在不改变…