• 注册 / 登录
  • 切换到窄版
  • 查看: 1838|回复: 0

    详解 C 语言源文件变成可执行文件的过程

    [复制链接]

    676

    主题

    690

    帖子

    6808

    积分

    版主

    Rank: 7Rank: 7Rank: 7

    积分
    6808
    发表于 2023-3-26 21:04:25 | 显示全部楼层 |阅读模式

    路线栈欢迎您!

    您需要 登录 才可以下载或查看,没有帐号?立即注册

    x
    前言

    很多小伙伴儿在学 C 语言时,用的是 IDE,比如 VS、Code::Blocks 等。每次写完代码点一下运行按钮或者按下相应的快捷键,就可以将程序跑起来,操作非常简单。所以他们就产生了一个错觉:C 语言源代码可以直接运行。

    1.png

    IDE:Integrated Development Environment,集成开发环境,是一个用于提供程序开发环境的应用程序,一般包括代码编辑器、编译器、调试器等工具。它为程序开发提供一条龙服务,开发者无需切换使用其他开发工具,可以大幅提升开发效率和体验。

    很明显这是错误的,C 语言是一门编译型的语言,其源代码是不能直接运行的,必须通过编译和链接处理,转化为可执行文件后才能运行。这个可执行文件就是我们所说的程序,在 Windows 系统中的文件后缀名为 .exe。

    IDE 为了提升开发效率,将背后的细节处理过程都包装起来了,让我们可以一键搞定。但站在技术学习的角度,我们很有必要详细了解一下 C 语言源文件转化为最终可执行文件的整个过程。知其然知其所以然,以后遇到项目构建问题也能自己分析解决。

    第 1 步:预处理(Preprocess)

    也称为预编译,顾名思义就是在编译之前处理一下,即对源文件(.c)和头文件(.h)里面的所有预处理命令进行相应处理,并删除所有注释内容。所谓预处理命令,就是代码中那些以 # 开头的行,比如常见的头文件包含(#include)、宏定义(#define)等。
    不同种类的预处理命令的处理方式各不相同,比如头文件包含预处理命令(#include)就是把目标头文件的内容读取出来替换掉当前行,宏定义预处理命令(#define)就是把代码中的所有宏名替换为对应的宏值。
    以 gcc 编译器为例,假设源文件为 test.c,可以通过下面的命令对源文件进行预处理:

    1. <p>gcc -E test.c -o test.i</p>
    复制代码

    -o 参数用于指定输出文件名,即把预处理结果存放到当前文件夹下的 test.i 文件中。如果不使用 -o 参数,预处理结果将会输出到屏幕上显示。

    第 2 步:编译(Compile)

    将预处理后的源文件(.i)经过一系列的词法分析、语法分析、语义分析以及优化,加工为当前机器支持的汇编代码文件(.s)。C 语言代码中的语法错误就是在这一步被检查出来的。

    对应的命令为:

    1. gcc -S test.i
    复制代码

    该命令执行后会在当前目录下生成 test.s 汇编代码文件。注意参数 -S 是大写的。
    汇编语言:一种针对底层硬件的低级编程语言,用助记符代表二进制机器指令。汇编代码和具体硬件平台息息相关,不具有移植性。它主要用于嵌入式系统底层开发,不过大部分应用场合都逐步被 C 语言取代,现在用的很少。

    第 3 步:汇编(Assemble)

    根据汇编语句和机器指令对照表,将上一步得到的汇编代码文件(.s)中的每一条汇编语句都翻译为对应的二进制机器指令,并存放到目标文件(.o)中。虽然目标文件里面存放的都是二进制机器指令,但它不能独立运行,因为它还依赖标准库等其它文件。

    对应的命令为:

    1. gcc -c test.s
    复制代码

    该命令执行后会在当前目录下生成 test.o 目标文件。

    第 4 步:链接(Link)

    将项目中的所有目标文件、标准库和指定的第三方库文件链接到一起,生成最终的可执行文件。标准库是必须的,并且会被默认链接。如果代码中调用了某个第三方库,就要通过 -l(指定库名)和 -L(指定库路径)参数指定链接它。如果需要的目标文件或库文件缺失,就会发生链接错误。

    本例很简单,就一个目标文件(复杂项目会有多个),也没有调用任何第三方库。对应的命令为:

    1. gcc test.o -o test.exe
    复制代码

    该命令执行后会在当前目录下生成最终的可执行文件 test.exe。通过 -o 参数可以指定生成的可执行文件的名字,默认为 test.out。Linux 系统上可执行文件的后缀名不要求一定为 .exe,可以为任意值或没有。

    经过上面 4 步的依次处理,就可以将源文件转化为最终的可执行文件,当然也可以一步到位。

    1. gcc test.c -o test.exe
    复制代码

    我们现在用的编译器(比如 gcc 等)不仅仅能进行编译处理,还包含了预处理、汇编和链接功能。在实际开发时,我们都是一键构建,直接将项目中的源文件进行这 4 步处理转化为最终的可执行文件,且不会保留每一步产生的中间文件。

    通常我们将第 2 步和第 3 步合在一起统称为编译,最后用一张图总结整个过程。

    2.png
    作者:挨踢魔君

    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    小黑屋|路丝栈 ( 粤ICP备2021053448号 )

    GMT+8, 2024-12-22 14:26 , Processed in 0.047348 second(s), 21 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表