C语言程序的编译与链接

news2024/11/23 15:49:56

目录

  • 1.翻译环境和运行环境
  • 2.翻译环境
    • 2.1 预处理(预编译)
    • 2.2 编译
    • 2.3 汇编
    • 2.4 链接
  • 3.运行环境

1.翻译环境和运行环境

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

  • 翻译环境:在这个环境中源代码被转换为可执⾏的机器指令(⼆进制指令)。
  • 执行环境:⽤于实际执⾏代码。

在这里插入图片描述


2.翻译环境

翻译环境是怎么将源代码转换为可执⾏的机器指令的呢?本篇文章将讲解一下翻译环境在这个过程中对源代码做的事。

翻译环境由两个大的过程组成:

  • 编译
  • 链接

而其中编译过程又可分为:预处理(预编译)编译汇编三个过程。


在这里插入图片描述


  • 一个c语言的项目中可能有多个源文件( .c文件 ),那它们会如何生成可执行程序( .exe文件)呢?

  • 首先它们会单独经过编译器处理生成对应的目标文件。(如 test.c -> test.obj)

    • 注:在Windows环境下的⽬标⽂件的后缀是.obj,Linux环境下⽬标⽂件的后缀是.o
  • 多个⽬标⽂件和链接库⼀起经过链接器处理⽣成最终的可执⾏程序。

    • 链接库是指运⾏时库(它是⽀持程序运⾏的基本函数集合)或者第三⽅库。(库文件的使用需要链接库)
  • 如果将编译拆分成三部分,那就变成以下过程:

在这里插入图片描述

2.1 预处理(预编译)

预处理阶段,源⽂件和头⽂件会被处理成为.i为后缀的⽂件。

处理规则如下:

  • 将所有的 #define 删除,并展开所有的宏定义。

  • 处理所有的条件编译指令,如: #if、#ifdef、#elif、#else、#endif

  • 处理 #include 预编译指令,将包含的头⽂件的内容插⼊到该预编译指令的位置(直接将头文件内容全部拷贝过来,并删除 #include 这一行)。这个过程是递归进⾏的,也就是说被包含的头⽂件也可能包含其他⽂件。

  • 删除所有的注释

  • 添加⾏号和⽂件名标识,⽅便后续编译器⽣成调试信息等。

  • 或保留所有的 #pragma 的编译器指令,编译器后续会使⽤。

2.2 编译

编译阶段,会生成由汇编语言构成的汇编文件( .s 文件)

生成汇编文件的过程中会进行如下处理:

  • 语法分析
  • 词法分析
  • 语义分析
  • 符号汇总(将全局变量名或者函数名汇总,包括 main ,局部变量因为在编译过程还没有创建,只有运行时才创建,所以不汇总)

2.3 汇编

汇编阶段,会将汇编代码处理成机器指令(二进制指令),生成 .o 文件( Linux 环境下)或者 .obj 文件( Windows 环境下)。

同时还会形成符号表,符号表就是将之前汇总的符号与一个地址关联起来。
对一个函数名:

  • 如果文件中定义了该函数,则关联一个有效的地址(可以找到该函数并使用)
  • 如果文件中只声明了该函数,则关联一个无效的地址(给什么样的无效地址取决于编译器)。

2.4 链接

链接是将多个源文件和链接库一起经过链接器处理生成可执行文件的过程。

该阶段主要进行:

  • 段表合并
  • 符号表的合并和符号表的重定位

段表合并:经过汇编过程,生成的 .o 文件,如 test.oadd.o 等,都有具体的格式:elf 格式,格式将文件划分为不同的区域,存放不同的内容,所以将多个源文件合并生成可执行程序时,需要将相同的区域的内容合并到一起,这一过程称为合并段表

符号表的合并和重定位:汇编阶段每个源文件都形成了对应的符号表,在链接阶段需要将它们合并起来。下面举一个例子:

例如:在一个c语言项目中有 add.c (只定义了 函数 add)和 test.c (声明了但没有定义函数 add,且有主函数 main)。
add.o 中的符号表:

add -> 0x11111111  //(假设的有效地址)

test.o 中的符号表:

add -> 0x00000000   //(假设的无效地址)
main -> 0x22222222   // (假设的有效地址)

因为 test.o 中和 add.o 中都有 add ,但是 add.o 中的地址是无效的,所以合并后取有效地址,这个过程叫符号表的重定位

add -> 0x11111111  //(假设的有效地址)
main -> 0x22222222   // (假设的有效地址)

有了符号表程序就可以找到对应的函数,如果合并之后某个符号的地址仍是无效的,则程序无法找到这个符号的定义并报错

add -> 0x00000000   //(假设的无效地址)
main -> 0x22222222   // (假设的有效地址)

合并后这样的符号表程序就会报错。

3.运行环境

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

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

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

maven { url ‘https://www.jitpack.io‘ }在新版Android Studio中的位置

Android Studio升级到Arctic Fox后,一些配置项的位置都做了改变。 github上的很多库通过JitPack.io发布的,引用这些库时,除了在模块的build.gradle文件中加入依赖,还要在项目的build.gradle文件中加入maven { url ‘https://www.j…

Spring事务简介,事务角色,事务属性

1.Spring事务简介 事务作用:在数据层保障一系列的数据库操作同成功同失败Spring事务作用:在数据层或业务层保障一系列的数据操作同成功同失败 public interface PlatformTransactionManager{void commit(TransactionStatus status) throws TransactionE…

【算法每日一练]-动态规划(保姆级教程 篇17 状态压缩)

目录 今日知识点: 把状态压缩成j,dp每行i的布置状态,从i-1和i-2行进行不断转移 把状态压缩成j,dp每行i的布置状态,从i-1行进行状态匹配,然后枚举国王数转移 POJ1185:炮兵阵地 思路: 题目:互…

IP地址中网络号的查看方法

IP地址是互联网中设备的标识,它由网络号和主机号两部分组成。网络号用于标识设备所连接的网络,而主机号则用于标识该网络中的具体设备。了解如何查看IP地址中的网络号对于网络管理员和需要进行网络配置的用户来说至关重要。虎观代理将介绍几种常见的查看…

第⑫讲:Ceph集群OSD扩缩容中Reblanceing数据的重分布

文章目录 1.Reblanceing数据重分布的概念2.验证Reblanceing触发的过程3.Reblanceing细节4.临时关闭Reblanceing机制 1.Reblanceing数据重分布的概念 当集群中OSD进行扩缩容操作后,会触发一个Reblanceing数据重分布的机制,简单的理解就是将扩缩容前后OSD…

windows下使用ZLMediaKit-API+FFmpeg+opengl拉取解码播放流媒体

ZLMediaKit简介 ZLMediaKit是一个基于C11的高性能运营级流媒体服务框架,和SRS类似,功能强大,性能优异,提供多种支持多种协议(RTSP/RTMP/HLS/HTTP-FLV/WebSocket-FLV/GB28181/HTTP-TS/WebSocket-TS/HTTP-fMP4/WebSocket-fMP4/MP4/…

插入排序解读

在众多的排序算法中,插入排序以其直观易懂和在某些特定场景下的高效性而备受青睐。今天,我们就来深入探索一下插入排序的原理、实现方式以及它的优缺点。 一、算法原理 插入排序相当于打牌中抓牌插入的方式。插入排序的工作方式是通过构建有序序列&…

007高并发内存池_回收内存

​🌈个人主页:Fan_558 🔥 系列专栏:高并发内存池 🌹关注我💪🏻带你学更多知识 文章目录 前言一、ThreadCache回收内存二、CentralCache回收内存2.1 建立映射 三、PageCache回收内存 小结 前言 …

Google视觉机器人超级汇总:从RT、RT-2到AutoRT/SARA-RT/RT-Trajectory、RT-H

前言 随着对视觉语言机器人研究的深入,发现Google的工作很值得深挖,比如RT-2 ​想到很多工作都是站在Google的肩上做产品和应用,​Google真是科技进步的核心推动力,做了大量大模型的基础设施,服(推荐重点关注下Googl…

C语言——关于指针运算的例题分析

1.指针运算中关于 sizeof 和 strlen 的例题分析 1. sizeof(数组名),这⾥的数组名表⽰整个数组,计算的是整个数组的⼤⼩。 2. &数组名,这⾥的数组名表⽰整个数组,取出的是整个数组的地址。 3. 除此之外所有的数组名都表⽰…

SpringBoot之SpringBoot整合MyBatis

本章详情 使用SpringBoot和MyBatis通过注解的方式操作数据库使用SpringBoot和MyBatis通过XML配置文件的方式操作数据库 项目搭建 1. 打开idea,选择Create New Project 2.选择Spring Initializer,然后点击Next 3.填写组织,坐标等信息,然后点击Next 4.选…

信息泄露漏洞的JS整改方案

引言 🛡️ 日常工作中,我们经常会面临线上环境被第三方安全厂商扫描出JS信息泄露漏洞的情况,这给我们的系统安全带来了潜在威胁。但幸运的是,对于这类漏洞的整改并不复杂。本文将介绍几种可行的整改方法,以及其中一种…

LeetCode-347. 前 K 个高频元素【数组 哈希表 分治 桶排序 计数 快速选择 排序 堆(优先队列)】

LeetCode-347. 前 K 个高频元素【数组 哈希表 分治 桶排序 计数 快速选择 排序 堆(优先队列)】 题目描述:解题思路一:哈希表记录出现次数,然后用最小堆取,因为每次都是弹出最小的,剩下的一定是K…

【鸿蒙开发】系统组件Column

Column组件 Column沿垂直方向布局的容器。 接口: Column(value?: {space?: string | number}) 参数: 参数名 参数类型 必填 参数描述 space string | number 否 纵向布局元素垂直方向间距。 从API version 9开始,space为负数或者…

error:LNK2005 已经在*.obj中定义 的原因分析及对策

LNK2005是一个重复定义错误,造成LNK2005主要有以下几种情况: 目录 全局变量的重复定义 情况A:全局变量在.cpp文件中的多次声明 情况B:变量名重复 头文件的包含重复 解决方案 #ifndef标识符宏定义 pragma once预编译 头文件…

C++第十五弹---string基本介绍(一)

✨个人主页: 熬夜学编程的小林 💗系列专栏: 【C语言详解】 【数据结构详解】【C详解】 目录 1、什么是STL 2、STL的版本 3、STL的六大组件 4、STL的重要性 5、如何学习STL 6、STL的缺陷 7、为什么学习string类 7.1、C语言中的字符串…

autodl常用工具命令

以下内容仅为当前认识,可能有不足之处,欢迎讨论! 文章目录 tar/zip命令镜像版本参考torch包全版本下载torch和cuda版本对应conda命令conda打包conda 环境重命名conda环境复制和转移conda环境删除 tar/zip命令 参考链接 文件目录打包&#x…

macU盘在电脑上读不出来 u盘mac读不出来怎么办 macu盘不能写入 Tuxera NTFS for Mac免费下载

对于Mac用户来说,使用U盘是很常见的操作,但有时候可能会遇到Mac电脑无法读取U盘的情况,这时候就需要使用一些特定的工具软件来帮助我们解决问题。本文就来告诉大家macU盘在电脑上读不出来是怎么回事,u盘mac读不出来怎么办。 一、m…

PTA题解 --- 静静的推荐(C语言)

今天是PTA题库解法讲解的第七天,今天我们要讲解静静的推荐,题目如下: 解题思路: 这个问题的核心在于如何在满足给定条件的情况下,最大化推荐学生的数量。首先,我们需要过滤出所有天梯赛成绩不低于175分的学…

3.2.k8s搭建-kubeadm

目录 一、虚拟机准备 二、所有节点环境准备 1.所有节点做hosts解析 2.所有节点重新命名 3.所有节点安装docker 4.所有节点为docker做linux内核转发 5.所有节点配置docker 6.所有节点关闭swap分区 7.所有节点验证网卡硬件编号是否冲突 8.所有节点配置允许iptables桥接…