C语言版Hello World的编译过程

32 sec read

C语言基本上大学都教过,但是很多人应该和我一样学习的时候还使用的是Windows平台,对于其中要用到的编译等知识都不了解。今天就针对这种情况来重新学习一遍C语言。

以上代码应该是最简单的C语言程序了,将上面的内容报错为hello.c,并通过gcc去编译它,具体使用到的指令为:

$ gcc -g -Wall hello.c -o hello

该命令将文件‘hello.c’中的代码编译为机器码并存储在可执行文件 ‘hello’中。机器码的文件名是通过 -o 选项指定的。该选项通常作为命令行中的最后一个参数。如果被省略,输出文件默认为 ‘a.out’。如果当前目录中与可执行文件重名的文件已经存在,它将被覆盖。

选项 -Wall 开启编译器几乎所有常用的警告。编译器有很多其他的警告选项,但 -Wall 是最常用的。默认情况下GCC 不会产生任何警告信息。当编写 C 或 C++ 程序时编译器警告非常有助于检测程序存在的问题。 注意如果有用到math.h库等非gcc默认调用的标准库,请使用-lm参数。

选项 “”-g”” 表示在生成的目标文件中带调试信息,调试信息可以在程序异常中止产生core后,帮助分析错误产生的源头,包括产生错误的文件名和行号等非常多有用的信息。

执行万上述指令后我们发现有报错,具体内容为:

hello.c:2:1: 警告: 返回类型默认为‘int’ [-Wreturn-type]
hello.c: 在函数‘main’中:
hello.c:5:1: 警告: 在有返回值的函数中,控制流程到达函数尾 [-Wreturn-type]

解决上诉问题的方法非常的简单,只要将代码修改为:

不管采用上诉的哪种代码,在命令行直接执行编译出来的hello文件,即可看到输出的hello world。下面就来细讲整个编译的过程。

compilation

上图是一个hello的c程序由gcc编译器从源码文件hello.c中读取内容并将其翻译成为一个可执行的对象文件hello的过程。这个过程包含了几个阶段:

1、预处理过程:预处理(cpp)根据以字符#开头的命令,修改原始的C程序。比如hello.c中的第一行的#include <stdio.h> 命令告诉预处理器读取系统头文件stdio.h的内容,插入到程序文本中。结果就得到里另一个C程序,通常是以*.i作为文件扩展名。

可通过执行如下指令获得:gcc -E hello.c -o hello.i

用记事本打开,可查看到如下的内容:

以上部分代码可以看出除了#include <stdio.h>指令之外其他指令并未被改变。

2、编译阶段:编译器将文本文件hello.i翻译成文本文件hello.s,它包含一个汇编语言程序。汇编语言程序中的每条语句都以一种标准的文件格式确切地描述了一条低级机器语言指令。

可通过如下指令获得:gcc -S hello.c -o hello.s

用记事本打开,可查看到如下的内容:

3、汇编阶段:汇编器将hello.s翻译成机器语言指令,把这些指令打包成一种可重定位目标程序的格式,并把结果保存在hello.o中,hello.o是一个二进制文件,它的字节编码是机器语言指令,而不是字符。

可通过如下指令获得:gcc -c hello.c,最终生成的hello.o文件需要使用objdump打开,具体指令为:objdump -d hello.o

获取的内容为:

4.、链接阶段:hello.c程序中调用了printf函数,而printf函数存在于一个名为printf.o的单独的预编译好的目标文件中,而这个文件必须以某种方式合并到我们的hello.o程序中。连接器就负责处理这种合并,结果就得到hello文件,它是一个可执行文件,可以被加载到内存中由系统执行。

使用的指令为:gcc hello.o -o hello,最终生成了一个hello文件,同样此hello文件可用通过objdump打开:objdump -d hello

打开后的内容为:

经过上面四个过程,我们就可以把一个源代码文件编译成机器能运行的可执行文件。这个可执行文件刚开始是保存在磁盘上,当计算机要运行这个程序的时候,hello就被加载到内存中,接着程序指令被不断复制到寄存器中由CPU来执行,最后把”hello world”从寄存器中打到显示设备上。这就是hello程序整个执行过程。

大致的过程就这么多,关于中间涉及到的其他内容由于篇幅的限制,下篇文章再详述~尽请期待~

打赏作者
微信支付标点符 wechat qrcode
支付宝标点符 alipay qrcode

C语言学习:size_t

在学习C语言的时候,遇到了一个新的数据类型size_t,截止目前也没有完全理清这个类似的具体场景及出现的原因。
44 sec read

C语言学习:main()函数的正确写法

C语言虽然是一门古老的语言,但是其标准一直在完善,所以很多以前支持的语法在到当前已经不能在使用了。 C语言的版
41 sec read

Scipy数学函数的Scala实现

最近在推进项目的时候,遇到需要将线下的Python代码转化成线上的集群代码,由于机器代码环境是Scala,所以
4 min read

发表评论

电子邮件地址不会被公开。 必填项已用*标注