假如在Linux系统终端,我们创建了一个.c文件,如:main.c,我们可以通过以下指令来运行它。

gcc -o main main.c

这个时候会增加一个叫做 main 的文件。然后输入下一条指令:

./main

该C程序就会运行。

那么问题来了:为什么main.c文件不能直接运行?从main.c到main这一过程发生了什么?接下来,就让我们探究一下。

首先,我们要了解的是,上述运行过程其实包含了四个步骤,分别是:预编译(prepressing)、编译(complication)、汇编(assembly)、链接(linking)。接下来我们会对这四个过程进行具体分析。

一、预编译(prepressing)

我们首先创建一个C程序文件:love_01.c 其内容为:

#include<stdio.h>int main()
{int a = 2;int b = 5;printf("a + b = %d\n", a + b);return 0;
}

然后我们通过以下命令只对其进行预编译:

gcc   -o   love_01.i   -E   love_01.c

这时候我们生成了一个 .i 文件,这就是对C程序文件进行预编译后生成的文件,那么接下里我们看看这个文件里是什么内容:

我们发现,这个文件里总共有857行,但只有最后的几行是我们所写的代码,那前面这一大堆是什么来头呢?自然地,我们在main函数前面写的只有一个 #include<stdio.h> 而已,那前面这800多行难道是这个头文件的展开?

为了验证这一猜想,我们另外创建一个 love_02.c 的C程序文件,其内容为:

#include<stdio.h>
#include<stdlib.h>int main()
{int a = 2;int b = 5;    printf("a + b = %d\n", a + b);    return 0;
}

与love_01.c只有一处不同,就是多个#include<stdlib.h>,接下来还是按照老办法,只对其进行预编译,并查看生成的love_02.i文件.

我们发现,仅仅是加了一个头文件,预编译后就从857行增加到了1847行,而我们main函数的程序,还是只占了寥寥几行而已,结果不言而喻。

接下来,我们再创建一个love_03.c文件,其内容为:

#include<stdio.h>
#include<stdlib.h>#define c 0      //I am a studentint main()
{int a = 2 + c;int b = 5 + c;      //How are you?printf("a + b = %d\n", a + b + c);      //I am fine,thank you,and you?return 0;
}

这里我们是在love_02.c 的基础上添加了一个宏定义,#define c 0 和一些注释,这样预编译后的文件love_03.i会是什么样子呢?如下图所示:

我们惊奇地看到,其行数并没有发生改变,并且我们的宏名c也被替换成了0,注释也不见了。所以,预编译的过程中发生了什么呢?这里我用《程序员的自我修养》这本书里第39页的内容总结:

预编译过程主要处理那些源代码文件中以“#”开始的预编译指令,其主要处理规则如下:

1、将所有的“#define”删除,并且展开所有宏定义

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

3、 处理“#include”预编译指令,将被包含的文件插入到该预编译指令的位置。注意,这个过程是递归进行的,也就是说被包含的头文件可能还包含其他文件

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

5、 添加行号和文件名标识,比如上面的#3 “love_03.c” 2 ,以便于编译时编译器产生调试用的行号信息以及用于编译时产生编译错误或警告时能够显示行号

6、 保留所有的#pragma编译器指令,因为编译器需要使用它们

二、编译(complication)

还是使用love_01.c这个文件进行说明,刚才经过预编译这一过程,我们当前文件夹里已经有了love_01.c 和 love_01.i 这两个文件,接下来我们使用这条命令对 love_01.i 进行编译:

gcc  -olove_01.s  -S  love_01.i

然后生成love_01.s这个文件,就是编译后的结果,让我们来看一下里面是什么:

我相信如果学过汇编的同学对这些一定不会陌生,因为这就是汇编代码!

所以编译这一过程,是把预编译后的文件进行一系列词法分析、语法分析、语义分析及优化后生成的相应的汇编代码文件。

三、汇编(assembly)

还是继续针对love_01.c说明,我们当前有.c .和 .i以及 .s三个文件,接下来我们用以下指令对love_01.s进行汇编

gcc   -o   love_01.o   -c    love_01.s

生成的是love_01.o文件,让我们看看里面是什么内容吧:

这里面的内容让我们一头雾水,根本看不懂,这是很正常的,因为这些就是只有机器能读懂的机器指令。

通过汇编这一过程,将汇编代码转变成机器可执行的指令,每一个汇编语句几乎都对应一条机器指令。

而经过前面三个步骤:预编译,编译,汇编生成的 .o 文件我们叫做目标文件(object file)

那么现在,机器能识别这些机器指令了,是不是就能够运行了呢?很可惜,是不能的。那么原因是什么呢?上帝视角的我们自然知道还有一步链接的过程没进行,那么链接到底是什么?明明机器指令已经有了,为甚么计算机还是不能运行这个文件?目标文件和可执行文件的差别到底在哪里?

四、链接(linking)

链接这里是十分重要的知识点,首先发我们要知道目标文件里有什么,链接过程又做了那些事情,这些内容我会在之后的博客中进行详细补充,此处暂且不表,有兴趣的同学可以翻阅《程序员的自我修养》这本书。

1、

2、

铁马冰河入梦来——从源文件到可执行文件(待后续)相关推荐

  1. 打印helloworld,注释,从源文件到可执行文件

    2021年12月16日23:47:01 打印 helloworld 源码 C版 C++版 注释 单行注释 多行注释 方法一 方法二 方法三 从源文件到可执行文件 打印 helloworld 源码 C版 ...

  2. GCC:从源文件到可执行文件

    GCC:从源文件到可执行文件 假设我们有hello.c 文件 #include <stdio.h> int main(){printf("hello world!\n" ...

  3. 做一朵奔涌的浪花,铁马冰河不辞远

    大二下一个月了,到底是要来总结一下的. 文章目录 一.迷茫 二.其他 一.迷茫 这是我最近几天才感觉到的.新学期一开始,只能说自己对自己的方向更加确定了吧.舍友有玩JAVA的,有玩安卓的,但我自己还是 ...

  4. 我的冰河小海妖---正则表达式

    <铁马冰河入梦来> 也曾踏云入梦而来, 也曾漂洋过海而来, 有人说, 我的人生, 注定浪迹天涯, 谱一曲千古流芳, 可唯有你的陪伴, 才算锦上添花, 传一段盛世佳话, 曾经志在天下,书一卷 ...

  5. 罗振宇解读《今日简史》:21个议题就是21个千亿美金的机会

    这个时代,既然手机出新品可以开发布会,一个知识产品为什么不可以?一本新书.一堂新课,也应该有它诞生的证明. 所以在这个时代,我们有了好东西,就大胆地对用户喊出来. 今天我们要发布的是一本书,一本新书, ...

  6. js之dom操作练习 ---- js篇

    一.自动计数器 <html> <head> <script type="text/javascript"> var c=0 var t func ...

  7. 统计元音字母(JAVA)

    输入一个字符串,统计出其中元音字母的数量以及统计出每个元音字母的数量 import java.util.Scanner;public class Demo3 {public static void m ...

  8. 经典仿句100例_仿写句子_二年级仿写句子100例

    梅花:迎接它出生的不是和煦的春风,而是凛冽的北风:伴随它成长的不是温暖的春天,而是寒冷的冬天:滋润它成长的不是晶莹的甘露,而是肃杀的严霜:衬托它美姿的不是浓浓的绿意,而是寒彻的白雪.花坛暖房里,它不开 ...

  9. 北大青鸟 JQuery制作特效 第二章 (上机练习

    北大青鸟 JQuery制作特效 第二章 (上机练习 练习一丶制作简易的当当购物车页面 <!DOCTYPE html> <html> <head lang="en ...

最新文章

  1. 如何用FAPROTAX预测微生物群落功能
  2. wait notify的使用
  3. cocos2dx - Lua 语言
  4. h2 不能访问localhost_SpringBoot2.x系列教程44--H2数据库详解及搭建Web控制台
  5. android 函数式编程_Android开发人员的函数式编程-第1部分
  6. 微型计算机杂志合订本,微型计算机(2008上半年合订本)(上下)(附光盘)
  7. leetcode刷题——415. 字符串相加
  8. 【原创】搭建spark环境二
  9. React中的图片懒加载
  10. mysql in查询效率真的低_MySql中in查询效率低的替代方法
  11. MTK 11A MAINMENU
  12. 数据结构队列顺序循环队列、加入、删除、取头元素
  13. pigeon主题如何将顶部图片扩大
  14. Java虚拟机——Parallel Scavenge收集器
  15. MR(混合现实)无绿幕拍摄
  16. 利用鸿蒙开发新闻头条
  17. 在系统中自主实现全国行政区域结构化管理
  18. 机器人控制算法四之迭代法求解四轴机器人逆解
  19. 法国留学DIY的必备条件和步骤
  20. 【Python】根据汽车品牌列表及链接地址分别获取对应子品牌及车系数据列表

热门文章

  1. java实现动漫论坛
  2. 计算机 智能化 论文范文大全集,智能论文范文
  3. python fsolve说明_python用fsolve、leastsq对非线性方程组求解
  4. 服务器发送携带ULR的短信到手机
  5. 离散数学自考学习笔记
  6. 树图数据库的建立和原理
  7. 【C++ STL】vector模拟实现
  8. 开题报告不知道怎么写?
  9. BISTU-(1)-4-17-2016
  10. MySQL的视图的相关介绍