C语言编译与链接的基础知识

1:关于程序的编译环境与执行环境

        在c语言的实现中,存在着两种不同的环境:

        1:编程环境,在这个环境中编译器会将源代码转换成可执行的计算机指令。

        2:执行环境,它用于执行代码。

2:编译与链接

        c语言的代码想要执行,首先会将每一个单独的源文件(例如:test.c文件)通过编辑器经过一系列操作最终形成目标文件及后缀名为.obj(在windows环境下),接着在将链接库通过连接器与目标文件进行结合形成为可执行文件.exe。

                

        

        通过上图示例可以得知一个.c的文件想要执行起来就需要通过编译与链接最终形成.exe文件。

2.1:详解编译:

          

       C语言的编译一共分为三个步骤,第一为预处理也叫预编译,第二为编译,第三会汇编。

2.1.1:预处理

        在C语言中,预处理是编译过程中的第一个阶段,用于对源代码进行预处理操作,而在预处理的时候,编译器会在编译的目录下生成后缀为.i文件,这个文件就是预处理后的文件。

                                

        小编在vs2022的环境下写了一段简单代码,那么如果想观察编译器对这段代码是如何进行预编译的时候,鼠标右击文件,接着找到属性选项,在属性选项里选择预处理器选项,选择预处理到文件。

        

        开启选项后,此时在运行代码,程序会报错,原因是无法打开.obj文件。是因为当我们打开处理到文件的选项后,编译器不会执行预处理后的步骤也就不会形成.obj文件,所以无法打开。此时我们打开文件目录,找到.i后缀的文件进行观察。

                

        此时观察点i文件会发现,在预编译时文件就生成了一万多行的代码,但明明只写了几行的代码为什么会产生这么多呢?原因是当预处理器处理#include指令时,会将被包含的头文件的内容完全复制到包含它的地方,因而在写代码的时候不要重复包含头文件,避免增加程序运行时间,影响程序的效率。

        

        那么这时候将预处理后的代码与源代码相比,可以发现原先的#define 的指令没有了,但代码中NUM符号全部被替换成了10,以及注释指令也没有了。

          由此可以得出预处理器主要执行以下几种功能:

  1. 宏替换:将源代码中定义的宏(使用#define指令定义)在预处理阶段进行替换;
  2. 文件包含:将其他文件中的内容包含到当前文件中(使用#include指令);
  3. 注释移除:将注释从源代码中移除。

2.1.2:编译

        编译就是将预处理后的文件进行一系列的分析:语法分析词法分析语义分析,将c语言代码转换成相应的汇编代码。

        词法分析

  • 词法分析是编译器的第一个阶段,也称为扫描。
  • 在这个阶段,源代码会被分割成具有语义意义的单词,如关键字、标识符、运算符和常量等。
  • 词法分析器会根据事先定义的规则来识别这些单词,并将它们转化为一个个的标记

        语法分析

  • 语法分析是在词法分析之后的阶段,也称为解析。
  • 在这个阶段,编译器会使用上一步生成的单词来构建语法树,这个语法树是以表达式为节点的语法树

                        

        语义分析:

  • 语义分析是在语法分析之后的阶段。
  • 在这个阶段,编译器会对语法树进行分析,进行类型检查和语义错误的检测。

                

        

       总结:编译过程就是将c语言代码转换成汇编代码,同时进行词法分析,语法分析,语义分析

        

2.1.3:汇编

        汇编就是把汇编代码转换成机器指令,每一条汇编码几乎都对应一条机器指令

2.2:链接

        链接是将多个源文件中编写的程序代码以及所需的库文件、系统函数等组合成一个可执行程序或库的过程。在编译过程中,每个源文件都会被独立编译成目标文件.obj,而链接过程则将这些目标文件以及其他必要的文件组合起来,解析它们之间的引用关系,最终生成可执行文件或者库文件。而链接的主要任务有,符号解析符号表的合并与重定位

        通过上图示例,小编在一个项目里面创建了两个.c的文件,在链接的过程中,text文件里的main标识符与Add标识符会进行符号解析,将这两个标识符解析成地址后形成一个符号表,又因为extern Add 声明了Add函数是一个外部函数 所以Add的地址为0地址,接着解析add文件里的Add标识符,形成符号表,最后将两个符号表进行合并,发现在text文件里声明的Add标识符刚好与add文件里的Add标识符对的上,那么这两个标识符地址就进行重定位,最终合成合成了一个新的符号表,那么程序就会继续执行下去并不会报错。

        

        

        可以看出如果此时将add.c文件的Add函数改成add,那么在合并符号表的时候编译器并没有从外部找到声明的标识符而进行了报错,原因是声明的标识符与add.c里的标识符不同。

        综上所述,源文件在编译器的编译时候会经过预处理,编译,汇编与链接等一系列复杂的过程后最终形成.exe可执行文件

3.运行环境:

        1.   程序必须载入到内存中。在有操作系统的环境中:这个操作由操作系统完成。如果在独立环境中,程序的载入必须由手工完成或通过可执行代码嵌入只读内存条中,例如嵌入式。

        2.程序的执行开始,接着调用main函数执行。

        3.开始执行代码,这时候程序会创建一个运行堆栈,用于存储存储局部变量与返回值,同时程序也可以创建一个静态内存(static),存储于静态内存里的变量只有在程序结束时候才会进行销毁。

        4.程序正常结束或者程序报错(erro)中止。

相关推荐

  1. C语言编译

    2024-06-06 15:20:03       9 阅读
  2. c编译执行

    2024-06-06 15:20:03       37 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-06-06 15:20:03       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-06-06 15:20:03       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-06-06 15:20:03       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-06-06 15:20:03       20 阅读

热门阅读

  1. STM32_SPI

    STM32_SPI

    2024-06-06 15:20:03      8 阅读
  2. 什么是接地电阻柜呢?

    2024-06-06 15:20:03       9 阅读
  3. 解决QT QMessageBox 弹出需点击两次才能关闭问题

    2024-06-06 15:20:03       9 阅读
  4. delphi 3层源码

    2024-06-06 15:20:03       9 阅读
  5. react+vite创建

    2024-06-06 15:20:03       10 阅读
  6. 三生随记——理发店诡事

    2024-06-06 15:20:03       12 阅读
  7. 深入探索 Linux 命令:usermod

    2024-06-06 15:20:03       12 阅读
  8. ASP.NET第四章 Response、Request和Server对象

    2024-06-06 15:20:03       8 阅读
  9. linux学习:进程通信 管道

    2024-06-06 15:20:03       10 阅读
  10. LeetCode # 1070. 产品销售分析 III

    2024-06-06 15:20:03       11 阅读
  11. golang结构与接口方法实现与交互使用示例

    2024-06-06 15:20:03       10 阅读
  12. 设计模式之观察者模式

    2024-06-06 15:20:03       8 阅读