编译和链接详解

文章目录

  • 前言
  • 翻译环境和运行环境
    • 翻译环境和运行环境图解
  • 翻译环境
    • 编译
      • 预处理(预编译)阶段
      • 编译
      • 汇编
    • 链接
  • 运行环境
  • 总结


前言

提示:这里可以添加本文要记录的大概内容:

在软件开发的世界中,编译和链接是构建程序的两个关键步骤。编写代码只是整个过程的一部分,而将源代码转换成可执行文件的过程涉及到编译器和链接器的协同工作。理解编译和链接的机制不仅有助于提高代码的执行效率,还有助于解决各种与构建过程相关的问题。本文将深入探讨编译和链接的原理,帮助读者更好地理解这两个必不可少的开发环节。


提示:以下是本篇文章正文内容,下面案例可供参考

翻译环境和运行环境

在ANSI C的任何一种实现中,存在两个不同的环境

  1. 第一种是翻译环境,在这个环境中源代码被转换成可执行的机器指令。
  2. 第二种是执行环境,它用于实际执行代码。

关于ANSI C帮大家补充一下,就当是拓展内容,看看就好!

ANSI C(American National Standards Institute C)是一种标准化的C语言规范,由美国国家标准协会(ANSI)制定。该标准于1989年首次发布,是对早期C语言的规范化和标准化。ANSI C的目标是提供一个一致的编程接口,使得C语言在不同的计算机系统上能够保持一致性,增强了可移植性。

ANSI C引入了一些新的特性和改进,以便更好地支持结构化编程和提高代码的可读性。此外,它还定义了标准C库,包含了一组通用的函数,例如输入输出、字符串处理等,使得这些函数在不同的系统上有着相同的接口和行为。

ANSI C标准后来成为国际标准(ISO C),最新版本是ISO C17,它继续保持了与ANSI C相近的特性,为C语言的发展奠定了基础。

翻译环境和运行环境图解

在这里插入图片描述

翻译环境

翻译环境是如何将源代码转换成可执行的机器指令的?接下来,我们就详细讲解一下翻译环境所做的那些事情。
翻译环境是由编译链接两个过程组成的,而编译又可以分解成:预处理(也叫预编译)、编译、汇编三个过程
在这里插入图片描述

一个C项目中,通常会有对个.c文件,那么多个.c文件是如何生成可执行程序的呢?

  • 多个.c文件单独经过编译处理,产生对应的目标文件
  • 在windows环境下的目标文件后缀是(.obj),linux下目标文件后缀是.o
  • 多个目标文件和链接库一起经过链接器处理生成最终的可执行程序。
  • 链接器是指运行时库(它支持程序运行的基本函数集合)或者第三方库。

如果要把编译的过程展开来说,就是如下过程

在这里插入图片描述

编译

预处理(预编译)阶段

预处理阶段主要处理那些源文件中#开始的预编译指令。比如#include,#define,处理的规则如下:

  • 将所有的 #define 删除,并展开所有的宏定义。
  • 处理所有的条件编译指令,如: #if、#ifdef、#elif、#else、#endif 。
  • 处理#include 预编译指令,将包含的头文件的内容插入到该预编译指令的位置。这个过程是递归进行的,也就是说被包含的头文件也可能包含其他文件。
  • 删除所有的注释
  • 添加行号和文件名标识,方便后续编译器生成调试信息等。
  • 或保留所有的#pragma的编译器指令,编译器后续会使用。
    经过预处理后的.i文件中不再包含宏定义,因为宏已经被展开。并且包含的头文件都被插入到.i文件中。所以当我们无法知道宏定义或者头文件是否包含正确的时候,可以查看预处理后的.i文件来确认。

编译

编译过程是将高级程序语言代码转换为目标机器代码的过程,通常包括词法分析、语法分析、语义分析和优化等阶段。下面是这三个部分的简要说明和示例:

  1. 词法分析(Lexical Analysis):

    • 任务: 将源代码转换为令牌序列,识别出程序中的基本单元,如关键字、标识符、运算符等。
    • 示例: 对于C语言代码片段int sum = a + b;,词法分析可能生成令牌序列为<int, keyword> <sum, identifier> <=, operator> <a, identifier> <+ , operator> <b, identifier> ;, delimiter>
  2. 语法分析(Syntax Analysis):

    • 任务: 将令牌序列转换为语法树,确保代码的结构符合语法规则。
    • 示例: 对于上述的令牌序列,语法分析可能生成以下语法树:
      (assignment_statement
         (variable_declaration
            (type int)
            (identifier sum))
         (expression
            (identifier a)
            (operator +)
            (identifier b)))
      
  3. 语义分析(Semantic Analysis):

    • 任务: 确保程序语义的正确性,检查变量的声明和使用、函数调用等语义规则。
    • 示例: 在语义分析阶段,编译器会检查是否定义了变量ab,以及它们的类型是否兼容。还会检查表达式中的运算符是否支持操作数的类型。
  4. 优化(Optimization):

    • 任务: 对生成的中间代码进行优化,提高程序执行效率。
    • 示例: 优化可能包括常量折叠、循环展开、代码内联等技术。例如,将循环中的常量计算移出循环体,以减少重复计算,从而提高程序的执行速度。

总体而言,这些阶段协同工作,确保源代码在转换为目标机器代码的过程中能够正确、高效地执行。

汇编

编译中的汇编过程通常包含了将汇编语言源代码翻译成机器代码的步骤。下面是一个简化的例子,以说明这个过程:

考虑以下C语言的简单源代码:(当前示例是在linux下演示的

// 文件: example.c
#include <stdio.h>

int main() {
    printf("Hello, World!\n");
    return 0;
}

接下来,我们将通过编译器将这个C源代码编译成可执行文件的过程,其中包括了汇编过程:

  1. 预处理(Preprocessing):

    gcc -E example.c -o example.i
    

    这个步骤将执行预处理,处理#include指令、宏定义等,生成一个预处理后的文件 example.i

  2. 编译(Compilation):

    gcc -S example.i -o example.s
    

    编译器将 example.i 转换成汇编代码,保存在 example.s 文件中。

  3. 汇编(Assembly):

    gcc -c example.s -o example.o
    

    汇编器将 example.s 中的汇编代码转换成目标文件 example.o,其中包含了机器代码的二进制表示。

  4. 链接(Linking):

    gcc example.o -o example
    

    链接器将目标文件 example.o 与系统库和其他必要的文件链接,生成最终的可执行文件 example

现在,你可以执行生成的可执行文件 ./example,它将输出 “Hello, World!”。

在这个例子中,编译中的汇编过程主要涉及了编译器将高级源代码转换为汇编代码,然后通过汇编器将汇编代码转换为目标文件的过程。这个目标文件最终被链接器用于生成可执行文件。整个过程是复杂的,但这个例子可以帮助理解编译中的汇编过程的基本流程。

链接

链接过程是编译过程的最后一步,它负责将多个目标文件(Object Files)合并成一个可执行文件或者库文件。链接过程主要包括符号解析、地址绑定和重定位等步骤。下面是一个简化的例子,以说明链接过程:

假设我们有两个源文件,分别是 main.cfunctions.c

  1. main.c:

    // 文件: main.c
    #include <stdio.h>
    
    extern int add(int a, int b);
    
    int main() {
        int result = add(3, 4);
        printf("Result: %d\n", result);
        return 0;
    }
    
  2. functions.c:

    // 文件: functions.c
    int add(int a, int b) {
        return a + b;
    }
    

接下来,我们将通过编译器将这两个源文件编译成目标文件,然后通过链接器将它们合并为一个可执行文件:

  1. 编译(Compilation):

    gcc -c main.c -o main.o
    gcc -c functions.c -o functions.o
    

    这里,-c 选项表示编译成目标文件而不进行链接。分别编译 main.cfunctions.c 得到两个目标文件:main.ofunctions.o

  2. 链接(Linking):

    gcc main.o functions.o -o my_program
    

    链接器将 main.ofunctions.o 合并,并解析它们之间的符号引用关系。在这个例子中,main.o 中引用了 add 函数,而 functions.o 中定义了 add 函数。链接器将这两者关联起来,生成一个可执行文件 my_program

  3. 执行:

    ./my_program
    

    运行可执行文件,输出 “Result: 7”。

链接过程实际上包括了三个主要步骤:

  • 符号解析(Symbol Resolution): 解决目标文件中的符号引用,确保它们能够正确地与定义相匹配。

  • 地址绑定(Address Binding): 将符号绑定到实际的内存地址。这可能涉及到代码段、数据段等不同部分的地址绑定。

  • 重定位(Relocation): 调整目标文件中的地址,使其能够正确地在合并后的可执行文件中运行。这包括相对地址的调整等操作。

整个链接过程的目标是生成一个可执行文件,其中包含了所有必要的代码和数据,使得程序能够在内存中正确运行。这个过程也用于生成共享库等形式的输出。

运行环境

  1. 程序必须载入内存中。在有操作系统的环境中:⼀般这个由操作系统完成。在独立的环境中,程序的载入必须由手工安排,也可能是通过可执行代码置入只读内存来完成。
  2. 程序的执行便开始。接着便调用main函数。
  3. 开始执行程序代码。这个时候程序将使用⼀个运行时堆栈(stack),存储函数的局部变量和返回地址。程序同时也可以使用静态(static)内存,存储于静态内存中的变量在程序的整个执行过程⼀直保留他们的值。
  4. 终止程序。正常终止main函数;也有可能是意外终止。

总结

编译和链接作为软件开发过程中不可或缺的步骤,承担着将高级源代码转化为可执行文件的责任。编译器负责将源代码转换为中间代码,而链接器则将各个模块组合成最终的可执行文件。通过深入了解编译和链接的原理,开发者能够更好地优化代码、解决依赖关系、提高执行效率。在不同的编程语言和开发环境中,编译和链接的实现方式可能存在差异,但它们共同构成了程序构建的核心。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/338361.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【GitHub项目推荐-开源的任务管理工具】【转载】

推荐一个开源的任务管理工具&#xff0c;该工具会提供各类文档协作功能、在线思维导图、在线流程图、项目管理、任务分发、即时 IM&#xff0c;文件管理等等。该开源项目使用到 Vue、Element-UI、ECharts 等技术栈。 开源地址&#xff1a;www.github.com/kuaifan/dootask 预览地…

5G_系统同步机制(八)

BBU和RRU的同步机制 为什么要做到系统同步 在TDD模式下工作时&#xff0c;为了避免相邻小区之间的干扰&#xff0c;近距离的所有gNB在任何时间点都必须具有相同的传输方向(DL或UL)。这样做的必要条件是在BTS之间同步SFN (System Frame number)和time Slot。此外&#xff0c;由…

meshgrid contour contourf

meshgrid contour contourf 参考video: https://www.bilibili.com/video/BV1qW411A775/?spm_id_from333.337.search-card.all.click&vd_sourced171c31a396363b8ea8c0e92a59cee6b 官方文档: https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.contourf.html#ma…

嵌入式-C语言-江科大-数据类型宏定义#define关键字typedef结构体

这是C语言中高级相关知识&#xff0c;在单片机中实战的一些用法 参考C语言江科大视频的学习笔记&#xff0c;详细举例子并且完整记录up的想法&#xff0c;包括内容有c语言数据类型&宏定义#define&关键字typedef&结构体&预处理指令 文章目录 一:C语言数据类型二…

idea 折叠某段代码 这段特定某段代码

如何折叠IntelliJ IDEA代码片段_w3cschool ctrlALTT

HNU-数据挖掘-作业1

数据挖掘课程作业作业1 计科210X 甘晴void 202108010XXX 第一题 假设所分析的数据包括属性 age,它在数据元组中的值&#xff08;以递增序&#xff09;为13 ,15 ,16 ,16 ,19 ,20 ,20 ,21 ,22 ,22 ,25 ,25 ,25 ,25 ,30 ,33 ,33 ,35 ,35 ,35 ,35 ,36 ,40 ,45 ,46 ,52,70。 a.…

从零开始的OpenGL光栅化渲染器构建5-阴影

前言 阴影是光线被阻挡的结果&#xff1b;当一个光源的光线由于其他物体的阻挡不能够达到一个物体的表面的时候&#xff0c;那么这个物体就在阴影中了。阴影能够使场景看起来真实得多&#xff0c;并且可以让观察者获得物体之间的空间位置关系。 直接阴影 阴影映射(Shadow Ma…

C语言/c++指针详细讲解【超详细】【由浅入深】

指针用法简单介绍 指针&#xff0c;是内存单元的编号。 内存条分好多好多小单元&#xff0c;一个小单元有 8 位&#xff0c;可以存放 8 个 0 或 1&#xff1b;也就是说&#xff0c;内存的编号不是以位算的&#xff0c;而是以字节算的&#xff0c;不是一个 0 或 1 是一个编号&…

【题目】2023年国赛信息安全管理与评估正式赛任务书-模块3 CTF

全国职业院校技能大赛 高等职业教育组 信息安全管理与评估 任务书 模块三 网络安全渗透、理论技能与职业素养 竞赛相关资源资料可在文末关注公众号获得 比赛时间及注意事项 本阶段比赛时长为180分钟&#xff0c;时间为9:00-12:00。 【注意事项】 &#xff08;1&#xf…

做一个简单的倒计时

<div>距离过年还有:<span></span></div><script>let div document.querySelector("div");let span document.querySelector("span");// 获取未来时间戳let future new Date("2024-2-10 00:00:00");// 获取当下…

深度解析Python关键字:掌握核心语法的基石(新版本35+4)

目录 关键字 keyword 关键字列表 kwlist softkwlist 关键字分类 数据类型 True、False None 运算类型 and、or、not in is 模块导入 import 辅助关键字 from、as 上下文管理 with 占位语句 pass 流程控制 if、elif、else for while break、continue…

Android学习之路(23)组件化框架ARouter的使用

一、功能介绍 支持直接解析标准URL进行跳转&#xff0c;并自动注入参数到目标页面中支持多模块工程使用支持添加多个拦截器&#xff0c;自定义拦截顺序支持依赖注入&#xff0c;可单独作为依赖注入框架使用支持InstantRun支持MultiDex(Google方案)映射关系按组分类、多级管理&…

计组原理:系统概论与基本组成

系统概论与基本组成 系统概论硬件软件 计算机系统的层次结构系统复杂性的管理方法1&#xff1a;抽象 计算机的基本组成冯诺依曼计算机系统复杂性的管理方法 2&#xff1a;&#xff08;3’Y&#xff09; 计算机的工作步骤上机前的准备&#xff1a;计算机的解题过程存储器的基本组…

Java List集合使用 Comparator.comparing 排序报空指针异常问题

前言 有时候对一个List集合的某个字段进行排序的时候会报错&#xff0c;问题就是排序的那个字段可能是个空值&#xff0c;那么下面就是处理这种问题的方式&#xff0c;亲自测试有效。 参考 点击可跳转&#xff1a;Java List集合使用 Comparator.comparing 排序报空指针异常问…

TPM模拟器安装

目录 TPM模拟器安装 1&#xff09;安装配置所需依赖 2&#xff09;从官网下载TPM模拟器程序ibmtpm1332.tar.gz 3&#xff09;创建安装目录并将源码解压到对应目录 4&#xff09;进入解压后的目录&#xff0c;然后执行安装命令 5&#xff09;将tpm服务器添到Linux系统执行目…

gradle各版本下载地址

IDEA如何配置 Gradle&#xff08;详细版&#xff09;_idea gradle配置-CSDN博客 Gradle | Releases 参考以上文档

Python中函数的4种参数形式

默认参数的特点是在声明函数时使用“”来指定默认值。缺省参数指因为程序使用了默认值&#xff0c;使得函数调用时不必写出全部参数。 关键字参数可以摆脱位置匹配的限制&#xff0c;直接用变量名匹配。可变参数用于处理任意数量的参数&#xff0c;形参中带一个*&#xff0c;将…

小蓝和小桥的挑战*

题目 import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner sc new Scanner(System.in);int t sc.nextInt();sc.nextLine();while(t-- > 0) {int n sc.nextInt();sc.nextLine();int[] a new int[n];for(int i0;i<n;i)a[i…

Web server failed to start.Port xxxx was already in use.

目录 一、报错截图&#xff1a;二、解决方式 一、报错截图&#xff1a; 某端口被占用,导致出现如下报错&#xff1a; 二、解决方式 windowsR 输入cmd—>回车 如下图所示 查看被占用的端口的进程&#xff0c;如下图&#xff1a; netstat -ano |findstr 端口号结束这个进程…

恭喜CSDN,www.csdn.com域名买回来了!

摘要&#xff1a;www.csdn.com已经可以访问了&#xff0c;恭喜CSDN&#xff0c;迈出国际化的重要一步。 主页面浓浓的国际简约范 静态展示特点 著名的1024 day day up OpenStack & Open-Source 最后附上的是report 已经有众多支持者了&#xff0c;看排序。 博客不多&#…