C/C++ 程序执行的主要过程

发布于:2025-05-14 ⋅ 阅读:(18) ⋅ 点赞:(0)

在这里插入图片描述

预处理(Preprocessing)

  • 任务:
    处理源代码中以 # 开头的预处理指令,包括:
    • 头文件包含(#include):将头文件(如 stdio.h)的内容直接插入到源文件中。
    • 宏替换(#define):将代码中的宏定义(如 #define PI 3.14)进行文本替换。
    • 条件编译(#ifdef #else #endif 等):根据条件决定代码的保留或删除(例如,区分调试和发布版本的代码)。
  • 输出:生成一个经过预处理的中间文本文件(仍为可读文本,但已展开所有预处理指令)。

编译(Compilation)

  • 任务:
    将预处理后的代码转换为汇编语言代码。编译器会进行以下操作:
    • 词法分析:将代码分解成一个个单词(Token),例如识别关键字、变量名、操作符等。
    • 语法分析:检查代码是否符合 C/C++ 语法规则(如括号是否匹配、语句是否完整)。
    • 语义分析:检查代码的语义正确性(如变量是否先定义后使用、类型是否匹配)。
    • 中间代码生成与优化:生成中间表示代码,并进行优化(如删除无用代码、优化循环),最终转换为汇编语言。
  • 输出:生成汇编代码文件(如 Helloworld.s)。

汇编(Assembly)

  • 任务:
    汇编器(Assembler)将汇编语言代码转换为机器可识别的二进制目标文件(Object File,如 Helloworld.obj 或 Helloworld.o)。每个汇编指令会被映射为对应的机器码。
  • 输出:生成二进制目标文件,此时文件中可能仍包含对其他函数(如标准库函数 printf)的未解析引用。

链接(Linking)

  • 任务:
    链接器(Linker)将多个目标文件(包括自身代码生成的 .obj 和依赖的库文件)链接成一个可执行文件(如 Helloworld.exe)。分为两种方式:
    • 静态链接:将库函数的代码直接复制到可执行文件中,最终文件较大,但运行时无需依赖外部库。
    • 动态链接:仅记录对库函数的引用信息,运行时由操作系统加载对应的动态链接库(如 .dll 在 Windows 或 .so 在 Linux)。
      链接过程会解析目标文件中的外部符号引用(如解决 printf 的具体实现来自哪里)。
  • 输出:生成可直接运行的可执行文件。

运行(Execution)

  • 任务:
    操作系统加载可执行文件到内存中,创建进程,分配资源(如内存、文件句柄),然后执行程序的指令。程序从 main 函数开始执行,直到遇到 return 或 exit 等退出操作。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

总结

C代码编译成可执行程序经过4步:
1)预处理:宏定义展开、头文件展开、条件编译等,同时将代码中的注释删除,这里并不会检查语法
2)编译:检查语法,将预处理后文件编译生成汇编文件
3)汇编:将汇编文件生成目标文件(二进制文件)
4)链接:C语言写的程序是需要依赖各种库的,所以编译之后还需要把库链接到最终的可执行程序中去

分步编译

预处理:gcc -E hello.c -o hello.i
编  译:gcc -S hello.i -o hello.s
汇  编:gcc -c hello.s -o hello.o
链  接:gcc    hello.o -o hello
选项 含义
-E 只进行预处理
-S(大写) 只进行预处理和编译
-c(小写) 只进行预处理、编译和汇编
-o file 指定生成的输出文件名为 file
文件后缀 含义
.c C 语言文件
.i 预处理后的 C 语言文件
.s 编译后的汇编文件
.o 编译后的目标文件

在这里插入图片描述

一步编译

gcc hello.c -o demo(还是经过:预处理、编译、汇编、链接的过程):
在这里插入图片描述