1.4 C 程序的编译过程与 CLion 调试技巧

目录

1 程序的编译过程

1.1 编写源代码

1.2 预处理(Preprocessing)

1.3 编译(Compilation)

1.4 汇编(Assembly)

1.5 链接(Linking)

1.6 执行

2 编译过程的输入输出文件概览

3 断点及调试步骤

4 什么是调试


1 程序的编译过程

        程序的编译过程是一个从人类可读的源代码转换为计算机可直接执行的机器代码的过程。这个过程大致可以分为以下几个步骤,以 C 语言程序(如 main.c )为例来说明:

1.1 编写源代码

        程序员使用文本编辑器(如 Notepad++、Vim、Sublime Text 或专门的 IDE 如 CLion、Visual Studio、Visual Studio Code、Xcode、Eclipse 等)编写源代码,这些源代码文件通常具有特定的扩展名,如 .c 对于 C 语言。

1.2 预处理(Preprocessing)

        编译器在编译之前,首先会进行预处理。这一步会处理源代码中的预处理指令,如包含头文件(#include)、宏定义(#define)、条件编译(#ifdef、#ifndef、#endif)等。预处理后,生成一个包含了所有必要信息的新文件,但通常这个步骤的输出文件对程序员不可见

1.3 编译(Compilation)

        经过预处理后的代码会被编译器进一步处理,即编译过程。编译器将源代码转换成汇编语言代码(Assembler code),这一步是源代码到机器码的中间步骤。汇编语言是一种低级语言,比机器码稍高级,但仍然是针对特定 CPU 架构的。

1.4 汇编(Assembly)

        汇编器将汇编语言代码转换成机器码(Machine Code),即 0 和 1 的序列,这是 CPU 能直接执行的指令集。这一步生成的机器码是特定于目标平台(如 x86、ARM 等)的。

1.5 链接(Linking)

        如果程序中使用了外部库或定义了多个源文件( .c 文件),则需要进行链接。链接器将多个目标文件(Object Files,即 .o 或 .obj文件,它们是编译和汇编过程的结果)以及所需的库合并成一个可执行文件(在 Windows 下通常是 .exe,在 Unix/Linux/Mac 下通常是没有扩展名的)。链接过程中还会解决程序中的函数调用、变量引用等依赖关系。

1.6 执行

        生成的可执行文件可以被加载到内存中,由 CPU 执行。在操作系统中,这通常通过双击文件图标、在命令行中输入文件名并回车或使用操作系统的其他机制来完成。


编译过程的输入输出文件概览

步骤输入文件输出文件
1. 预处理(Preprocessing)hello.c(C 语言源代码文件)hello.i(预处理后的源代码文件,有时直接跳过此步骤的显式输出,但内部处理是存在的)
注意:在某些编译环境中,预处理后的文件可能不会被显式地保存为 .i 文件,而是直接在内存中处理。
2. 编译(Compilation)hello.i(预处理后的源代码文件,或直接从 hello.c 进入此步骤)hello.s(汇编语言源代码文件)
3. 汇编(Assembly)hello.s(汇编语言源代码文件)hello.o(目标代码文件,二进制形式)
4. 链接(Linking)hello.o(目标代码文件) + 其他目标代码文件/库文件hello(或 hello.exe,在 Windows 系统下)可执行文件(二进制形式)

注意

  1. 在某些编译环境中,特别是当使用集成开发环境(IDE)时,预处理后的文件(.i)和汇编语言源代码文件(.s)可能不会被显式地生成和保存。这些步骤通常在内部完成,并且用户只能看到最终的输出(即可执行文件)。

  2. 在 Windows 系统下,最终的可执行文件通常具有 .exe 扩展名,而在 Unix/Linux 系统下,则可能没有特定的扩展名,或者使用如 .out 的扩展名(这取决于具体的编译器和链接器设置)。

  3. 链接阶段还可能涉及生成其他类型的文件,如符号表、重定位信息等,但这些文件通常不是最终用户直接关心的内容。

  4. 上述过程是一个简化的描述,实际的编译过程可能更加复杂,包括优化、调试信息生成等多个子步骤。然而,从文件输入输出的角度来看,上述归纳已经涵盖了主要的内容。

        扩展:下面列出了在 Linux 终端中使用 gcc 编译器编译 C 语言程序的多种指令:


        1.偷懒法
        gcc hello .c
        默认生成 a.out
        起不到见名知意的作用,不建议 !
    
        2.分步法
        预处理: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
        比较细致,但实际使用不建议,比较麻烦 !
 
        3.一步到位法
        gcc hello.c -o hello
        编译并生成对应名称的可执行程序,见名知意,建议使用 !!!

        

        通过上面这些命令也可以看出 C 语言程序的编译过程。


3 断点及调试步骤

        在 CLion 中,程序在我们点击绿色三角形按钮时,一下子就运行到最后一步了,速度非常快,如果最终输出的结果和我们预期的不一样,我们如何查找代码的哪一步出了问题呢?

        秘诀就是让它运行慢下来(类似于魔术慢放),一次只让程序运行一步,如何让程序运行慢下来,那就是断点调试

         如下图所示,在编程界面上,首先定位到位置 1(即行号右侧的灰色区域),左键点击那里将添加一个红色圆圈作为断点,这个断点标记了调试时程序应当暂停执行的起始点。紧接着,点击位置 2(即小虫子图标),这是调试启动的按钮,点击后,程序将按照设置的断点逐步执行,从而开启详细的调试之旅。

        当点击虫子按钮后,出现蓝色条,代表程序已经开始了调试,从这一步开始运行,但是当前蓝色行所在处的代码还未得到运行,如下图所示:

        注意:蓝条所在行,表示此语句还未得到执行。 

        点击一次上图的步过按钮(也称:单步运行按钮,即上图 2 指向的折弯箭头)后,程序会运行一步,从第 4 行运行到了第 5 行,得到如下图:


4 什么是调试

        调试(Debugging)是软件开发过程中一个至关重要的环节,它涉及到查找、识别并修正程序中的错误(或称为“bug”)。这些错误可能导致程序无法正确执行其预期的功能,或者产生非预期的结果

        在调试过程中,程序员会仔细分析程序的运行过程,特别是那些可能导致问题的部分。由于程序在执行时会进行各种计算,这些计算会改变程序中变量的值,因此,监视这些变量的变化是调试过程中的一个重要手段。

        变量监视窗口(或称为“调试窗口”、“观察窗口”等)是许多集成开发环境(IDE)和调试工具提供的一个功能,它允许程序员在程序运行时实时查看变量的值。当程序执行到某个特定点时,程序员可以暂停程序的执行(这通常通过设置断点来实现),然后查看此时程序中各个变量的值。如果发现某个变量的值不符合预期,那么很可能就是这里出了问题,也就是找到了一个 bug。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Thanks_ks

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值