C是一种中级语言,它需要编译器才能将其转换为可执行代码,以便程序可以在我们的计算机上运行。
我们如何编译和运行C程序?
以下是我们在具有gcc编译器的Ubuntu计算机上使用的步骤。
- 我们首先使用编辑器创建一个C程序,然后将文件另存为filename.c
$ vi filename.c
- 右图显示了一个将两个数字相加的简单程序。
- 然后使用以下命令进行编译。
$ gcc –Wall filename.c –o filename
- 选项-Wall启用所有编译器的警告消息。建议使用此选项来生成更好的代码。
选项-o用于指定输出文件名。如果我们不使用此选项,那么将生成名称为a.out的输出文件。
- 编译可执行文件生成后,我们使用以下命令运行生成的可执行文件。
$ ./filename
编译过程中有什么内容?
编译器将C程序转换为可执行文件。 C程序成为可执行文件有四个阶段:
- 前处理
- 汇编
- 集会
- 连结中
通过执行以下命令,我们将获得当前目录中的所有中间文件以及可执行文件。
$gcc –Wall –save-temps filename.c –o filename
以下屏幕快照显示了所有生成的中间文件。
让我们一个个地看看这些中间文件包含什么。
前处理
这是传递源代码的第一阶段。此阶段包括:
- 删除评论
- 扩展宏
- 扩展包含的文件。
- 条件编译
预处理后的输出存储在filename.i中。我们来看一下filename.i的内容:使用$ vi filename.i
在上面的输出中,源文件充满了很多信息,但是最后保留了我们的代码。
分析:
- 现在printf包含a + b而不是add(a,b),这是因为宏已扩展。
- 评论被剥离。
- #include
丢失了,相反,我们看到了很多代码。因此头文件已被扩展并包含在我们的源文件中。
编译中
下一步是编译filename.i并生成一个;中间编译输出文件filename.s 。该文件在汇编级说明中。让我们使用$ vi filename.s浏览该文件
快照显示它是汇编语言可以理解的汇编语言。
集会
在此阶段,将filename.s用作输入,并由汇编程序将其转换为filename.o 。该文件包含机器级别的说明。在此阶段,仅将现有代码转换为机器语言,诸如printf()之类的函数调用无法解析。让我们使用$ vi filename.o查看此文件
连结中
这是最后一个阶段,在此阶段中完成了所有函数调用及其定义的链接。链接器知道所有这些功能的实现位置。 Linker还会做一些额外的工作,它会在程序的开始和结束时向我们的程序中添加一些额外的代码。例如,有一个代码需要设置环境,例如传递命令行参数。使用$ size filename.o和$ size filename可以轻松地验证此任务。通过这些命令,我们知道输出文件如何从目标文件增加到可执行文件。这是因为链接器在我们的程序中添加了额外的代码。