C是一种高级语言,需要编译器将其转换为可执行代码,以便程序可以在我们的机器上运行。

我们如何编译和运行C程序?

以下是我们在带有gcc编译器的Ubuntu机器上使用的步骤。

  • 编译C程序: – 幕后故事-IDC帮帮忙我们首先使用编辑器创建一个C程序,并将文件保存为filename.c
     $ vi filename.c

    右图显示了一个添加两个数字的简单程序。

  • 编译C程序: – 幕后故事-IDC帮帮忙然后使用下面的命令编译它。
     $ gcc -Wall filename.c -o filename

    选项-Wall启用所有编译器的警告消息。建议使用此选项以生成更好的代码。
    选项-o用于指定输出文件名。如果我们不使用此选项,则会生成名为a.out的输出文件。

  • 编译C程序: – 幕后故事-IDC帮帮忙编译后生成可执行文件,我们使用下面的命令运行生成的可执行文件。
     $ ./filename

编译过程中有什么内容?

编译器将C程序转换为可执行文件。C程序有四个阶段成为可执行文件:

  1. 前处理
  2. 汇编
  3. 部件
  4. 链接

通过执行以下命令,我们获得当前目录中的所有中间文件以及可执行文件。

 $ gcc -Wall -save-temps filename.c -o filename

以下屏幕截图显示了所有生成的中间文件
编译C程序: – 幕后故事-IDC帮帮忙

让我们一个接一个地看看这些中间文件包含的内容。

前处理
这是传递源代码的第一个阶段。这一阶段包括:

  • 删除评论
  • 扩展宏
  • 扩展包含的文件。

预处理的输出存储在filename.i中。让我们看看filename.i中的内容:使用$ vi filename.i

编译C程序: – 幕后故事-IDC帮帮忙编译C程序: – 幕后故事-IDC帮帮忙

 

 

 

 

 

 

在上面的输出中,源文件中填充了大量的信息,但最后我们的代码被保留了下来。
分析:

  • printf现在包含一个+ b而不是添加(a,b),因为宏已经扩展了。
  • 评论被剥夺了。
  • #include <stdio.h>缺失,而我们看到很多代码。因此头文件已经扩展并包含在我们的源文件中。

编译
下一步是编译filename.i并生成一个; 中间编译输出文件filename.s。此文件位于汇编级指令中。让我们使用$ vi filename.s来查看这个文件

编译C程序: – 幕后故事-IDC帮帮忙

快照显示它是汇编语言,汇编器可以理解。

部件
在此阶段,filename.s作为输入,并由汇编程序转换为filename.o。该文件包含机器级指令。在此阶段,只将现有代码转换为机器语言,不解析像printf()这样的函数调用。让我们使用$ vi filename.o查看此文件

编译C程序: – 幕后故事-IDC帮帮忙

链接
这是完成函数调用与其定义的所有链接的最后阶段。链接器知道所有这些功能的实现位置。Linker还做了一些额外的工作,它为我们的程序添加了一些额外的代码,这是程序启动和结束时所需要的。例如,有一个代码,用于设置环境,如传递命令行参数。使用$ size filename.o$ size filename可以轻松验证此任务。通过这些命令,我​​们知道输出文件如何从目标文件增加到可执行文件。这是因为链接器为我们的程序添加了额外的代码。 请注意,GCC默认执行动态链接,因此printf()在上面的程序中动态链接。
编译C程序: – 幕后故事-IDC帮帮忙