C 语言程序的编译过程

C 语言程序的编译过程

精选文章moguli202025-06-16 22:48:053A+A-

编译 C 程序

这里,我们所说的 C 语言程序的编译过程指的是从 C 语言源代码生成可执行程序(或库)的过程。通常,该过程要经过四个阶段,包括:

  • 预处理
  • 编译
  • 汇编
  • 链接

示例程序

举例来说,我们在名为 main.c 的源文件中输入下面一段简单代码,它在 main 函数中立即返回,返回值是用宏定义的 0 值。

  /*
     演示 C 语言程序的编译过程
   */
  
  #define SUCCESS 0
  
  int main()
  {   
      return SUCCESS;
  }

如果使用 gcc 编译器,我们可以逐步观察这个示例程序的编译过程。

预处理

gcc 用 -E 选项让编译器在预处理阶段结束后立即停止,不再往下执行编译。预处理过程对翻译单元中的代码进行词法和语义分析,其输出是程序在目标机器上的中间表示。

$ gcc -E main.c -o main.i
# 1 "main.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4 
# 1 "<command-line>" 2
# 1 "main.c"






int main()
{
 return 0;
}

预处理结束后,注释被替换成了空白行,宏定义被替换成了实际值。如果有 #include 预处理指令,该指令后面的头文件会被包含进中间文件。

编译

gcc 的 -S 选项让编译器在编译阶段结束后立即停止,不再往下执行汇编。编译阶段将预处理阶段生成的中间表示翻译为目标机器上的汇编代码。

$ gcc -S main.i -o main.s
    .file   "main.c"
    .text
    .globl  main
    .type   main, @function
main:
.LFB0:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    movl    $0, %eax
    popq    %rbp
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE0:
    .size   main, .-main
    .ident  "GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.12) 5.4.0 20160609"
    .section    .note.GNU-stack,"",@progbits

这里,汇编代码使用的是 AT&T 格式,我们看到寄存器 EAX 中被写入了 0 值,这是因为 main 函数最后的 ret 指令返回时会将寄存器 EAX 中的值作为返回值。

汇编

gcc 的 -c 选项在编译或汇编之后立即停止,不再往下执行链接。

$ gcc -c main.s -o main.o
$ file main.o
main.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped

这里,gcc 对汇编代码执行汇编生成了名为 main.o 的目标文件。由 file 命令可知,该文件是一个 ELF 格式的可重定位文件,下一步将对这个目标文件执行链接。

链接

不加任何选项时,gcc 对目标文件执行链接,生成可执行文件。

$ gcc main.o -o m

如以上步骤一样,我们用 -o 指定输出文件名称,这里是 m。该文件是一个可执行文件,尽管它不输出任何内容。

最后

需要注意的是,以上步骤只是为了演示 C 语言程序的编译过程。实际上,如果要从示例中的 main.c 生成可执行文件 m,我们只需要一条命令即可。

$ gcc main.c -o m2

之所以可以这样写是因为在正常情况下,对 C 源文件调用 gcc 会执行以上所有预处理、编译、汇编以及链接过程,直接生成可执行文件。

#头条创作挑战赛##C语言每日小知识#

点击这里复制本文地址 以上内容由莫古技术网整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!
qrcode

莫古技术网 © All Rights Reserved.  滇ICP备2024046894号-2