C语言程序编译与链接(拓宽视野的不二之选)

2024-03-28 02:12

本文主要是介绍C语言程序编译与链接(拓宽视野的不二之选),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 翻译环境和运行环境
    • 翻译环境
    • 预处理
    • 编译
    • 汇编
    • 链接
  • 运行环境

翻译环境和运行环境

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

第1种是翻译环境,在这个环境中源代码被转换为可执⾏的机器指					令(⼆进制指令)。
第2种是执⾏环境,它⽤于实际执⾏代码。

在这里插入图片描述

翻译环境

那翻译环境是怎么将源代码转换为可执⾏的机器指令的呢?这⾥我们就得展开开讲解⼀下翻译环境所做的事情。

其实翻译环境是由编译和链接两个⼤的过程组成的,⽽编译⼜可以分解成:预处理(有些书也叫预编译)、编译、汇编三个过程。

在这里插入图片描述

⼀个C语⾔的项⽬中可能有多个 .c ⽂件⼀起构建,那多个 .c ⽂件如何⽣成可执⾏程序呢?

  • 多个.c⽂件单独经过编译器,编译处理⽣成对应的⽬标⽂件。
  • 注:在Windows环境下的⽬标⽂件的后缀是 .obj ,Linux环境下⽬标⽂件的后缀是 .o
  • 多个⽬标⽂件和链接库⼀起经过链接器处理⽣成最终的可执⾏程序。
  • 链接库是指运⾏时库(它是⽀持程序运⾏的基本函数集合)或者第三⽅库。

在这里插入图片描述

预处理

在C语言中,预处理阶段是编译过程中的第一步,主要是通过预处理器对源代码进行处理,包括宏替换、头文件包含、条件编译等操作。下面详细解释一下预处理阶段的几个重要概念和操作:

  1. 头文件包含(Include Directives):
    #include 指令:用于包含其他文件的内容,分为尖括号包含系统头文件(如#include <stdio.h>)和双引号包含用户定义的头文件(如#include “myheader.h”)。

  2. 宏替换(Macro Replacement):
    宏定义:使用#define指令定义一个宏,如#define PI 3.14159。
    宏替换:预处理器会在编译前将代码中出现的宏名称替换为对应的值,比如将代码中的PI替换为3.14159。

  3. 条件编译(Conditional Compilation):
    条件编译指令:如#if、#ifdef、#ifndef、#elif、#else、#endif等,用于根据条件选择性地编译代码块。

  4. 其他预处理指令
    #undef:取消已定义的宏。
    #ifdef 和 #ifndef:判断某个宏是否已经定义。
    #error:在预处理时生成一个错误信息。
    #pragma:向编译器发出特定指令。

预处理器工作流程
1,将源文件中的头文件包含进来。
2,对源文件进行宏替换。
3,处理条件编译指令,根据条件编译部分代码。
4,生成一个经过预处理的中间文件,后缀为.i,供后续编译阶段使用。
5,删除所有的注释
6, 添加⾏号和⽂件名标识,⽅便后续编译器⽣成调试信息等

经过预处理后的.i⽂件中不再包含宏定义,因为宏已经被展开。并且包含的头⽂件都被插⼊到.i⽂件
中。所以当我们无法知道宏定义或者头⽂件是否包含正确的时候,可以查看预处理后的.i⽂件来确认。

编译

  1. 词法分析(Lexical Analysis):
    目的
    将源代码按照词法规则分割成单词(Token)序列。

    工作内容
    识别关键字、标识符、常量、运算符等单词,并生成对应的标记(Token)。生成标记流(Token Stream)作为下一步的输入。
    请添加图片描述

  2. 语法分析(Syntax Analysis):
    目的:
    将标记流转换成抽象语法树(Abstract Syntax Tree,AST)或语法分析树。

    工作内容:
    根据语法规则检查标记流是否符合语言语法规范。
    构建抽象语法树,表示源代码的结构和语法。

请添加图片描述

  1. 语义分析(Semantic Analysis):
    目的:
    进行语义检查,确保程序的语义正确。

    工作内容:
    检查类型匹配、变量的定义和使用是否正确。
    解析表达式,计算常量表达式的值。
    检查函数调用、返回值等语义正确性。

在这里插入图片描述

  1. 中间代码生成(Intermediate Code Generation):
    目的:
    将抽象语法树转换成中间代码表示。

    工作内容:
    生成一种中间表示形式,如三地址码、四元式等。
    将高级语言的结构转换成更加容易进行优化的形式。

  2. 优化(Optimization):
    目的:
    对中间代码进行优化,提高程序的执行效率。

    工作内容:
    利用各种优化技术,如常量传播、死代码删除、循环优化等,提高程序性能。
    生成更加高效的中间代码表示,以便后续的代码生成阶段使用。

  3. 代码生成(Code Generation):
    目的:
    将优化后的中间代码转换成目标机器代码。

    工作内容:
    根据目标机器的特性和指令集,将中间代码转换为机器指令。
    处理寄存器分配、指令选择等问题,生成最终的目标代码。

汇编

当将C语言代码转换为汇编语言时,主要涉及到编译器将高级语言代码翻译成等效的汇编语言代码。以下是详细介绍汇编语言的步骤:

  1. 指令表示
    汇编语言使用助记符(Mnemonics)来代表特定的机器指令,如mov用于数据传送、add用于加法运算等。
  2. 寄存器
    计算机有一组寄存器用于存储数据和执行操作,如通用寄存器(如eax、ebx)、数据寄存器(如edx)、地址寄存器(如esi、edi)等。
  3. 内存访问
    使用不同的寻址模式(如立即数偏移、寄存器间接寻址)来访问内存中的数据。
  4. 控制流
    汇编语言提供了跳转指令(如jmp)和条件跳转指令(如je、jne)来控制程序的执行流程。
  5. 过程调用
    使用call来调用函数,使用ret返回函数调用,需要处理函数参数传递和局部变量存储。
  6. 栈操作
    使用栈来保存函数调用过程中的返回地址、参数以及局部变量,通过push和pop指令来操作栈。
  7. 数据处理
    汇编语言提供了各种指令来进行数据处理,如移位指令、逻辑运算指令、算术运算指令等。
  8. 标志寄存器
    标志寄存器记录了运算结果的信息,如进位标志、零标志、符号标志等,影响程序的条件跳转。
    9.宏指令
    汇编语言支持宏定义,可以简化重复代码的书写,提高代码的可读性和维护性。

链接

链接是将多个目标文件(包括库文件)组合成一个可执行文件或动态链接库的过程。以下是链接过程的详细步骤:

  1. 符号解析(Symbol Resolution):
    目的:解析所有目标文件中的符号引用,确定它们对应的实际地址或存储位置。
    工作内容:
    遍历所有目标文件,收集每个符号(如函数名、全局变量名)的定义和引用信息。
    解析外部符号引用,确定这些符号最终在哪个目标文件或库文件中定义。
    2.重定位(Relocation):
    目的:修正目标文件中的相对地址,使其能正确地映射到最终的内存地址。
    工作内容:
    根据符号解析的结果,对所有涉及到的地址进行调整,确保它们能正确地指向符号的实际位置。
    生成包含所有修正地址的重定位表,以便在加载时进行修正。
  2. 地址空间分配(Address Allocation):
    目的:为目标文件中的变量和函数分配内存地址。
    工作内容:
    确定每个全局变量和函数在内存中的起始地址。
    处理重复定义和冲突,确保分配的地址不会发生重叠或冲突。
  3. 符号重命名(Symbol Renaming):
    目的:避免不同目标文件中的符号名字冲突。
    工作内容:
    对于静态链接,可以对不同目标文件中的相同符号进行重命名,以避免冲突。
    对于动态链接,通常使用全局符号表(Global Symbol Table)来管理符号名字,确保唯一性。
  4. 生成可执行文件或动态链接库(Executable/Dynamic Link Library Generation):
    目的:将经过符号解析、重定位等处理后的目标文件转换为最终的可执行文件或动态链接库。
    工作内容:
    将已经修改过的目标文件内容按照特定的格式组合成可执行文件或动态链接库。
    对于可执行文件,可能还需要添加一些运行时所需的信息,如程序入口点等。
  5. 符号表生成(Symbol Table Generation):
    目的:生成最终可执行文件或动态链接库中的符号表,记录符号名字和对应的地址信息。
    工作内容:
    生成包含所有符号信息的符号表,以便在加载时进行符号解析和重定位。

运行环境

1,程序必须载⼊内存中。在有操作系统的环境中:⼀般这个由操作系统完成。在独⽴的环境中,程序的载⼊必须由⼿⼯安排,也可能是通过可执⾏代码置⼊只读内存来完成。

2, 程序的执⾏便开始。接着便调⽤main函数。

3,开始执⾏程序代码。这个时候程序将使⽤⼀个运⾏时堆栈(stack),存储函数的局部变量和返回地址。程序同时也可以使⽤静态(static)内存,存储于静态内存中的变量在程序的整个执⾏过程⼀直保留他们的值。

4,终⽌程序。正常终⽌main函数;也有可能是意外终⽌。

这篇关于C语言程序编译与链接(拓宽视野的不二之选)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/854140

相关文章

解决IDEA使用springBoot创建项目,lombok标注实体类后编译无报错,但是运行时报错问题

《解决IDEA使用springBoot创建项目,lombok标注实体类后编译无报错,但是运行时报错问题》文章详细描述了在使用lombok的@Data注解标注实体类时遇到编译无误但运行时报错的问题,分析... 目录问题分析问题解决方案步骤一步骤二步骤三总结问题使用lombok注解@Data标注实体类,编译时

C语言小项目实战之通讯录功能

《C语言小项目实战之通讯录功能》:本文主要介绍如何设计和实现一个简单的通讯录管理系统,包括联系人信息的存储、增加、删除、查找、修改和排序等功能,文中通过代码介绍的非常详细,需要的朋友可以参考下... 目录功能介绍:添加联系人模块显示联系人模块删除联系人模块查找联系人模块修改联系人模块排序联系人模块源代码如下

基于Go语言实现一个压测工具

《基于Go语言实现一个压测工具》这篇文章主要为大家详细介绍了基于Go语言实现一个简单的压测工具,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录整体架构通用数据处理模块Http请求响应数据处理Curl参数解析处理客户端模块Http客户端处理Grpc客户端处理Websocket客户端

使用SQL语言查询多个Excel表格的操作方法

《使用SQL语言查询多个Excel表格的操作方法》本文介绍了如何使用SQL语言查询多个Excel表格,通过将所有Excel表格放入一个.xlsx文件中,并使用pandas和pandasql库进行读取和... 目录如何用SQL语言查询多个Excel表格如何使用sql查询excel内容1. 简介2. 实现思路3

Go语言实现将中文转化为拼音功能

《Go语言实现将中文转化为拼音功能》这篇文章主要为大家详细介绍了Go语言中如何实现将中文转化为拼音功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 有这么一个需求:新用户入职 创建一系列账号比较麻烦,打算通过接口传入姓名进行初始化。想把姓名转化成拼音。因为有些账号即需要中文也需要英

Go语言使用Buffer实现高性能处理字节和字符

《Go语言使用Buffer实现高性能处理字节和字符》在Go中,bytes.Buffer是一个非常高效的类型,用于处理字节数据的读写操作,本文将详细介绍一下如何使用Buffer实现高性能处理字节和... 目录1. bytes.Buffer 的基本用法1.1. 创建和初始化 Buffer1.2. 使用 Writ

深入理解C语言的void*

《深入理解C语言的void*》本文主要介绍了C语言的void*,包括它的任意性、编译器对void*的类型检查以及需要显式类型转换的规则,具有一定的参考价值,感兴趣的可以了解一下... 目录一、void* 的类型任意性二、编译器对 void* 的类型检查三、需要显式类型转换占用的字节四、总结一、void* 的

C语言线程池的常见实现方式详解

《C语言线程池的常见实现方式详解》本文介绍了如何使用C语言实现一个基本的线程池,线程池的实现包括工作线程、任务队列、任务调度、线程池的初始化、任务添加、销毁等步骤,感兴趣的朋友跟随小编一起看看吧... 目录1. 线程池的基本结构2. 线程池的实现步骤3. 线程池的核心数据结构4. 线程池的详细实现4.1 初

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

安卓链接正常显示,ios#符被转义%23导致链接访问404

原因分析: url中含有特殊字符 中文未编码 都有可能导致URL转换失败,所以需要对url编码处理  如下: guard let allowUrl = webUrl.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else {return} 后面发现当url中有#号时,会被误伤转义为%23,导致链接无法访问