欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

一探·编译与连接

发布时间:2025/3/15 编程问答 30 豆豆
生活随笔 收集整理的这篇文章主要介绍了 一探·编译与连接 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

1.前言

对于平常应用程序的开发,我们很少需要关注编译与链接过程,因为通常的开发环境都是流行的集成开发环境,比如Visual Studio、Delphi等。他们往往将编译与链接的过程放在了一起,称为构建(Build)。 IDE和编译器提供的默认配置、编译、链接参数对于大部分的应用程序开发而言应经足够使用了。但只在这样的开发过程我们往往会被这些复杂的集成工具所提供的强大功能所迷惑,很多系统软件的运行机制或机理被掩盖,其程序的很多莫名其妙的错误让我们无所适从。此外,面对程序运行时种种性能瓶颈我们束手无策。这是因为我们往往仅看到了问题的现象,却没有看清问题的本质,所有这些问题的的本质就是然间运行背后的机理及支撑软件运行的各种平台与工具。如果能够深入了解这些机制,那么解决这些问题我们就游刃有余啦。

2.被掩藏了的过程是什么?

C语言中的经典“HelloWorld”程序如下所示: #include<stdio.h> int main() {printf("HelloWorld\n");return 0; } 当我们采用集成开发环境进行编译时,实际上可以分解为四个步骤:预处理Preprecessing)、编译(Compilation)、汇编(Assembly)、链接(Linking)。利用GCC编译,其编译过程如下图所示:

预编译 首先是源代码文件hello.cpp和相关头文件(如stdio.h等)被编译器cpp预编译成一个.ii文件。 预编译过程主要处理那些源代码文件中的以“#”开始的预编译指令。比如“#include”、“#define”等,主要处理规则如下: 1.将所有的“define”删除,并且展开所有的宏定义; 2.处理所有条件预编译指令,比如“#if”、“#ifdef”、“elif”、“#else”、“#endif”; 3.处理“#include”预编译指令,将被包含的文件插入到该预编译指令的位置,注意,这个过程是递归进行的。也就是说,被包含的文件可能还包含其他文件; 4.删除所有注释“//”和“/**/”; 5.添加行号和文件名标识,比如#2 “hello.cpp”2,以便于编译时编译器产生调试用的行号信息及用于编译时产生编译错误或警告时能够显示行号; 6.保留所有的#pragma编译器指令,因为编译器需要使用它们; 经过预编译后的.ii文件不包括任何宏定义,因为所有的宏已经被展开,并且包含的文件已经被插入到.ii文件中。所以当我们无法判断宏定义是否正确?头文件是否包含正确?可以查看预编译后的文件来确定问题。 编译 编译的过程就是把与处理完的文件进行一系列词法分析、语法分析、语义分析、及优化后生成相适应的汇编代码文件。这个过程往往是我们所说的整个程序构建的核心过程,也是最复杂的部分之一。这会涉及到编译原理的一些内容。得到的汇编输出文件为hello.s。 汇编 汇编器是将汇编代码转变成机器可以执行的指令,每一个汇编语句几乎都对应一条机器指令。所以汇编器的汇编过程相对于编译器来讲比较简单,他没有复杂的语法,也没有语义,也不需要做指令优化,只需要根据汇编指令和机器指令的对照表一一进行翻译就可以了,“汇编”这个名字也来源于此。 链接 链接过程通常会让人比较费解,为什么汇编器不直接输出可执行文件,而是输出一个目标文件呢???链接过程到底包含了什么内容???为什么要链接???这些问题看似简单,实际上涉及了编译、链接和库的内容,甚至是操作系统一些很底层的东西。我们仅仅记住一个事就好,可执行文件不仅仅需要一个目标文件(你的意图)还需要包含系统的库文件(可执行文件是在操作系统上运行的)!!!后面,我会用很大篇幅详细说明这个问题。 现在,我们基本上知道了一个源文件到可执行文件的过程,以及中间产生的临时文件。现在的问题是,编译器到底做了什么事???

总结

以上是生活随笔为你收集整理的一探·编译与连接的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。