C语言-从代码到程序的过程理解

C语言代码变成可运行的程序的流程

在这里插入图片描述

编译一个C程序可以分为四阶段,预处理阶段->生成汇编代码阶段->汇编阶段->链接阶段,这里以linux环境下gcc编译器为例。使用gcc时默认会直接完成这四个步骤生成可以执行的程序,但通过编译选项可以控制值进行某些阶段,查看中间的文件。

img

C语言程序可以使用在任意架构的处理器上,只要那种架构的处理器具有对应的C语言编译器和库,然后将C源代码编译、连接成目标二进制文件之后即可运行。

  1. 预处理:输入源程序并保存(.C文件)。
  2. 编译:将源文件转换成汇编代码(.s文件)的过程
  3. 汇编:汇编阶段是把编译阶段生成的”.s”文件转成二进制目标代码(.o文件)。
  4. 链接:将多个目标文件链接生成可执行文件( .EXE文件(windows),.out文件(Linux))。

预处理

预编译过程主要处理那些源代码文件中的以“#”开始的预编译指令,如“#include”、“#define'、”#if“,并删除注释行,还会添加行号和文件名标识以便于编译时编译器产生调试用的行号信息及用于编译时产生编译错误或警告时能够显示行号。经过预编译的.i文件不包含任何宏定义,因为所有的宏已经被展开并且包含的文件也已经被插入到.i文件中。所以当我们无法判断宏定义是否正确或头文件包含是否正确时,可以查看已编译后的文件来确认问题。通常是以 .i 作为文件扩展名

编译

有些地方直接把编译和汇编整合成一个流程。编译代表的是把源文件编译成中间代码文件,在 Windows 下也就是 .obj 文件,UNIX 下是 .o 文件,即 Object File

编译是将源文件转换成汇编代码的过程,具体的步骤主要有:词法分析 -> 语法分析 -> 语义分析及相关的优化 -> 中间代码生成 -> 目标代码生成(汇编文件.s)。

汇编

汇编阶段是把编译阶段生成的".s"文件转成二进制目标代码(".o"文件)。汇编器(as)将hello.s翻译成机器语言指令,把这些指令打包成一种叫做可重定位目标程序的格式,并将结果保存在目标文件hello.o中。hello.o文件是一个二进制文件,它的字节编码是机器语言指令而不是字符。如果我们在文本编译器中打开hello.o文件,看到的将是一堆乱码。

链接

对链接的简单认识

img

链接通俗的说就是把几个可执行文件。如果程序A中引用了文件B中定义的函数,为了A中的函数能正常执行,就需要把B中的函数部分也放在A的源代码中,那么将A和B合并成一个文件的过程就是链接了。有专门的过程用来链接程序,称为链接器。他将一些输入的目标文件加工后合成一个输出文件。这些目标文件中往往有相互的数据、函数引用。

链接的分类:按把A相关的数据或函数合并为一个文件的先后可以把链接分为静态链接和动态链接。

静态链接

在程序执行之前就完成链接工作。也就是等链接完成后文件才能执行。但是这有一个明显的缺点,比如说库函数。如果文件A 和文件B 都需要用到某个库函数,链接完成后他们连接后的文件中都有这个库函数。当A和B同时执行时,内存中就存在该库函数的两份拷贝,这无疑浪费了存储空间。当规模扩大的时候,这种浪费尤为明显。静态链接还有不容易升级等缺点。为了解决这些问题,现在的很多程序都用动态链接。

动态链接

和静态链接不一样,动态链接是在程序执行的时候才进行链接。也就是当程序加载执行的时候。果A和B都用到了库函数Fun(),A和B执行的时候内存中就只需要有Fun()的一个拷贝。和静态链接不一样,动态链接是在程序执行的时候才进行链接。也就是当程序加载执行的时候。还是上面的例子 ,如果A和B都用到了库函数Fun(),A和B执行的时候内存中就只需要有Fun()的一个拷贝。共享库函数

编译C语言的工具

各种工具之间的关系

套娃,一层一层地让下一层干活

1.gcc是GNU Compiler Collection(就是GNU编译器套件),也可以简单认为是编译器,它可以编译很多种编程语言(括C、C++、Objective-C、Fortran、Java等等)。

2.当你的程序只有一个源文件时,直接就可以用gcc命令编译它。

3.但是当你的程序包含很多个源文件时,用gcc命令逐个去编译时,你就很容易混乱而且工作量大

4.所以出现了make工具
make工具可以看成是一个智能的批处理工具,它本身并没有编译和链接的功能,而是用类似于批处理的方式—通过调用makefile文件中用户指定的命令来进行编译和链接的。

5.makefile是什么?简单的说就像一首歌的乐谱,make工具就像指挥家,指挥家根据乐谱指挥整个乐团怎么样演奏,make工具就根据makefile中的命令进行编译和链接的。

6.makefile命令中就包含了调用gcc(也可以是别的编译器)去编译某个源文件的命令。

7.makefile在一些简单的工程完全可以人工手下,但是当工程非常大的时候,手写makefile也是非常麻烦的,如果换了个平台makefile又要重新修改。

8.这时候就出现了Cmake这个工具,cmake就可以更加简单的生成makefile文件给上面那个make用。当然cmake还有其他功能,就是可以跨平台生成对应平台能用的makefile,你不用再自己去修改了。

9.可是cmake根据什么生成makefile呢?它又要根据一个叫CMakeLists.txt文件(学名:组态档)去生成makefile

10.到最后CMakeLists.txt文件谁写啊?亲,是你自己手写的。

11.当然如果你用IDE,类似VS这些一般它都能帮你弄好了,你只需要按一下那个三角形

img

gcc指令的使用

gcc是GNU Compiler Collection(就是GNU编译器套件),也可以简单认为是编译器,它可以编译很多种编程语言(括C、C++、Objective-C、Fortran、Java等等)。

gcc指令的一般格式为(man gcc 或者 gcc -h 查看更过选项帮助):

gcc [选项] 要编译的文件 [选项] [目标文件]
其中,目标文件可缺省,gcc默认生成可执行的文件名为:a.out(linux),a.exe(windows)
gcc main.c                               直接生成可执行文件a.out
gcc -o hello.exe main.c 				windows下直接生成可执行文件
gcc main.c  -o [自定义文件名]				直接生成可执行文件
gcc -E main.c -o hello.i                 生成预处理后的代码(还是文本文件)
gcc –S main.c -o hello.s                生成汇编代码
gcc –c main.c -o hello.o                生成目标代码

参考资料

开发一个c语言程序要经过哪四个步骤_百度知道

(5条消息) 深入理解程序从编译到运行_freeking101的博客-CSDN博客

运行C程序的步骤_GeoDoer-CSDN博客

(8 封私信 / 18 条消息) GCC 和 cmake的关系? - 知乎

原文地址:https://www.cnblogs.com/linzworld/p/13690620.html