在编译链接C语言的过程中,需要将我们编写的一个C程序(源代码)编译链接成一个可以在硬件上运行的程序(可执行代码)。编译是将文本形式的源代码翻译成机器语言形式的目标文件的过程。链接是组织目标文件、操作系统的启动代码和用于形成可执行代码的库文件的过程
从图中可以看出,整个代码的编译过程分为编译和链接两个过程。编译对应图中大括号括起来的部分,其余部分链接。
流程图如下:
编译过程可以分为编译和组装两个阶段。
编制
编译是读取源程序(字符流),分析其形态和语法,将高级语言指令转换成功能等价的汇编代码。源文件的编译过程包括两个主要阶段:
第一个阶段是预处理阶段,在正式编译阶段之前进行。在预处理阶段,源文件的内容将根据文件中已经放置的预处理指令进行修改。例如,#include指令是一个预处理指令,它将头文件的内容添加到。cpp文件。这种在编译前修改源文件的方法提供了很大的灵活性,以适应不同计算机和操作系统环境的限制。一个环境所需的代码可能不同于另一个环境所需的代码,因为可用的硬件或操作系统不同。在很多情况下,不同环境的代码可以放在同一个文件中,然后在预处理阶段修改代码以适应当前环境。
主要处理以下几个方面:
(1)宏定义指令,如#define a b
对于这种伪指令,预编译需要做的是用B替换程序中所有的A,但是作为字符串常量的A是不替换的。如果有# undef,就取消一个宏的定义,这样以后出现的字符串就不会被替换。
(2)条件编译指令,如#ifdef,#ifndef,#else,#elif,#endif等。
这些伪指令的引入使程序员能够通过定义不同的宏来决定编译器处理哪些代码。预编译器会根据相关文件过滤掉不必要的代码。
(3)头文件包含指令,如#include "FileName "或#include
在头文件中,大量的宏(最常见的是字符常量)一般是由伪指令#define定义的,其中也包含了各种外部符号的声明。使用头文件的主要目的是使一些定义对许多不同的C源程序可用。因为在需要使用这些定义的C源程序中,只需要添加一个#include语句,就不用在这个文件中重复这些定义了。预编译器会将头文件中的所有定义添加到它生成的输出文件中,供编译器处理。c源程序中包含的头文件可以由系统提供,这些头文件一般放在/usr/include目录下。#在程序中包含它们以使用尖括号(
(4)特殊符号。预编译器可以识别一些特殊符号。
比如源程序中出现的LINE标记会被解释为当前行号(十进制数),FILE会被解释为当前编译的C源程序的名称。预编译器将用适当的值替换出现在源程序中的这些字符串。
预编译程序所做的基本上是源程序的“替代”工作。这种替换后,生成没有宏定义、条件编译指令和特殊符号的输出文件。这个文件的意思和没有预处理的源文件是一样的,只是内容不同。接下来,这个输出文件将被翻译成机器指令作为编译器的输出。
编译优化第二阶段,预编译得到的输出文件中只有常量;比如数字、字符串、变量的定义,以及C语言关键字,比如main、if、else、for、while、{、}、+、-、*,等等。
编译器的工作是通过词法分析和语法分析,确认符合语法规则后,将所有指令翻译成等价的中间代码表示或汇编代码。
优化是编译系统中的一项难点技术。它涉及的问题不仅与编译技术本身有关,还与机器的硬件环境有关。优化的一部分是中间代码的优化。这种优化不依赖于特定的计算机。另一种优化主要针对目标代码的生成。
对于前者的优化,主要工作是删除常用表达式、循环优化(代码提取、强度弱化、循环控制条件转换、已知量组合等)。),复制传播,删除无用赋值等。
后一种优化与机器的硬件结构密切相关,最重要的考虑是如何充分利用机器各种硬件寄存器中存储的相关变量值来减少对内存的访问次数。此外,如何根据执行指令的机器硬件(如流水线、RISC、CISC、VLIW等)的特点调整指令也是一个重要的研究课题。)使得目标代码更短,执行效率更高。
1.《c程序 一个C程序(源代码)是如何运行在硬件上的?》援引自互联网,旨在传递更多网络信息知识,仅代表作者本人观点,与本网站无关,侵删请联系页脚下方联系方式。
2.《c程序 一个C程序(源代码)是如何运行在硬件上的?》仅供读者参考,本网站未对该内容进行证实,对其原创性、真实性、完整性、及时性不作任何保证。
3.文章转载时请保留本站内容来源地址,https://www.lu-xu.com/fangchan/707593.html