【C语言】编译和链接


目录

(一)编译

(1)预处理(预编译)

 (2)编译

i.词法分析

ii.语法分析

 iii.语义分析

(3)汇编

(二)链接

重定位


正文开始

(一)编译

        编译可以分解成:预处理(预编译),编译,汇编三个过程。

(1)预处理(预编译)

        在预处理(预编译)阶段,源文件和头文件会被处理成以( .i )为后缀的文件。

        在Linux的gcc编译环境下,可以使用命令行将名称为 “test.c” 的文件进行预处理,是用到的命令如下:

        gcc -E test.c -o test.i

         预处理阶段主要处理源文件中 #开头的预编译指令。比如:#define ,#include ,#if ,#ifndef 等。

         预处理阶段进行的处理规则主要如下:

  •  将所有的 #define 删除,并展开所有的宏定义;
  •  处理所有的条件编译指令,如: #if、#ifdef、#elif、#else、#endif ;
  •  处理#include预编译指令,将包含的头文件的内容插入到该预编译指令的位置。这个过程是递归进行的,也就是说被包含的头文件也可能包含其他文件;
  •  删除所有的注释;
  •  添加行号和文件名标识,方便后续编译器生成调试信息等;
  •  保留所有的#pragma的编译器指令,编译器后续会使用;


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

 (2)编译

         编译是将预处理之后的文件进行一系列的操作:词法分析,语法分析,语义分析及其优化生成相应的汇编代码文件。

         编译过程的命令如下:

        gcc -S test.i -o test.s

 即对预编译阶段生成的 test.i 编译 生成 test.s

假设存在这样一段代码,

arr[i] = (i+4)*(2+6);

如下演示一下汇编的整个过程:

i.词法分析

        扫描器通过对源代码程序的扫描,进行词法分析,把代码中的字符分割成一系列的记号(关键字,标识符,字面值,特殊字符等)。

        对上面的一段代码进行词法分析后会得到16个记号:

记号类型
arr标识符
[左方括号
i标识符
}右方括号
=赋值
(左圆括号
i标识符
+加号
4数字
)右圆括号
*乘号
(左圆括号
2数字
+加号
6数字
)右圆括号

ii.语法分析

         接下来,语法分析器通过对扫描产生的记号进行语法分析,从而产生语法树。并且这些树是以表达式为节点的树。

 iii.语义分析

         由语义分析器来完成语义分析,即对表达式的语法层面分析。编译器所能做的分析是语义的静态分析。静态语义分析通常包括声明和类型的匹配,类型的转换等。这个阶段会报告错误的语法信息。

 

 

(3)汇编

         汇编器将汇编代码转变成机器可执行的指令,每⼀个汇编语句几乎都对应⼀条机器指令。就是根据汇编指令和机器指令的对照表进行一一翻译,并不做指令优化。

 汇编的命令如下:

gcc -c test.s -o test.o

 可以通过反汇编来查看对应的汇编代码。

(二)链接

        链接是⼀个相对复杂的过程,链接的时候需要把许多文件链接在⼀起才生成可执行程序。不同操作系统的可执行程序的后缀不同:(windows-.obj )(Linux - .o)

 
        链接过程主要包括:地址和空间分配,符号决议和重定位等这些步骤。


        链接解决的是⼀个项目中多文件、多模块之间互相调用的问题

 比如在一个C的项目中有2个.c文件(test.c和add.c)

test.c

#include <stdio.h>//test.c//声明外部函数
extern int Add(int x, int y);//声明外部的全局变量
extern int g_val;int main()
{int a = 10;int b = 20;int sum = Add(a, b);printf("%d\n", sum);return 0;
}

add.c

int g_val = 2022;int Add(int x, int y)
{return x+y;
}

 我们已经知道,每个源文件都是单独经过编译器处理生成对应的目标文件。

        test.c 经过编译器处理⽣成test.c

        add.c 经过编译器处理⽣成add.o 

重定位


        我们在 test.c 中使⽤了 add.c 中的 Add 函数和 g_val 变量。
        我们在 test.c 中每⼀次使⽤ Add 函数和 g_val 的时候必须确切的知道 Add 和 g_val 的地址,但是由于每个⽂件是单独编译的,在编译器编译 test.c 的时候并不知道 Add 函数和 g_val变量的地址,所以暂时把调⽤ Add 的指令的⽬标地址和 g_val 的地址搁置。等待最后链接的时候由链接器根据引⽤的符号 Add 在其他模块中查找 Add 函数的地址,然后将 test.c 中所有引⽤到Add 的指令重新修正,让他们的⽬标地址为真正的 Add 函数的地址,对于全局变量 g_val 也是类似的⽅法来修正地址。

        这个地址修正的过程也被叫做:重定位


 ~完

未经作者同意禁止转载

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

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

相关文章

MPI 集体通信(collective communication)

1、MPI调用接口 &#xff08;1&#xff09;广播MPI_BCAST &#xff08;2&#xff09;散发MPI_SCATTER &#xff08;3&#xff09;收集MPI_GATHER &#xff08;4&#xff09;归约MI_REDUCE MPI_REDUCE将组内每个进程输入缓冲区中的数据按给定的操作op进行运算&#xff0c;并将…

什么是协方差矩阵?

协方差矩阵&#xff08;Covariance Matrix&#xff09;是一个用于衡量多个变量之间相互关系的工具&#xff0c;在统计学和数据分析领域中非常重要。这个矩阵展现了每一对变量之间的协方差。协方差是衡量两个变量如何一起变化的度量&#xff1b;如果两个变量的协方差是正的&…

第四篇:怎么写express的路由(接口+请求)

&#x1f3ac; 江城开朗的豌豆&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 &#x1f4dd; 个人网站 :《 江城开朗的豌豆&#x1fadb; 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! 目录 &#x1f4d8; 引言&#xff1a; &#x1f4…

【Flink-1.17-教程】-【四】Flink DataStream API(7)输出算子(Sink)

【Flink-1.17-教程】-【四】Flink DataStream API&#xff08;7&#xff09;输出算子&#xff08;Sink&#xff09; 1&#xff09;连接到外部系统2&#xff09;输出到文件3&#xff09;输出到 Kafka4&#xff09;输出到 MySQL&#xff08;JDBC&#xff09;5&#xff09;自定义 …

C++力扣题目416--分割等和子集 1049--最后一块石头的重量II

416. 分割等和子集 力扣题目链接(opens new window) 题目难易&#xff1a;中等 给定一个只包含正整数的非空数组。是否可以将这个数组分割成两个子集&#xff0c;使得两个子集的元素和相等。 注意: 每个数组中的元素不会超过 100 数组的大小不会超过 200 示例 1: 输入: […

k8s-配置管理

一、ConfigMap 1.1 创建ConfigMap 1.2 在环境种使用ConfigMap ConfigMap最为常见的使用方式就是在环境变量和Volume中引用。 1.3 在Volume中引用ConfigMap 在Volume中引用ConfigMap&#xff0c;就是通过文件的方式直接将ConfigMap的每条数据填入Volume&#xff0c;每条数据是…

【JavaSE篇】——数组的定义与使用

目录 本章的目标&#xff1a; &#x1f388;数组的基本概念 &#x1f36d;创建数组 &#x1f36d;数组的初始化 &#x1f36d;数组的使用 &#x1f449;数组中元素访问 &#x1f449;遍历数组 &#x1f388;数组是引用类型 &#x1f36d;初始JVM的内存分布 &#x1f…

【周赛】第382场周赛

&#x1f525;博客主页&#xff1a; A_SHOWY&#x1f3a5;系列专栏&#xff1a;力扣刷题总结录 数据结构 云计算 数字图像处理 力扣每日一题_ 从这一场&#xff08;第382场周赛&#xff09;周赛开始记录&#xff0c;目标是尽快达到准确快速AC前三道题&#xff0c;每场比赛…

Windows XP x86 sp3 安装 Google Chrome 49.0.2623.112 (正式版本) (32 位)

1 下载地址&#xff1b; https://dl.google.com/release2/h8vnfiy7pvn3lxy9ehfsaxlrnnukgff8jnodrp0y21vrlem4x71lor5zzkliyh8fv3sryayu5uk5zi20ep7dwfnwr143dzxqijv/49.0.2623.112_chrome_installer.exe 2 直接 双击 49.0.2623.112_chrome_installer.exe 安装&#xff1b; 3 …

第二百九十二回

文章目录 1. 概念介绍2. 方法与细节2.1 实现方法2.2 具体细节 3. 示例代码4. 内容总结 我们在上一章回中介绍了"如何混合选择图片和视频文件"相关的内容&#xff0c;本章回中将介绍如何混合选择多个图片和视频文件.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1…

BGP:04 fake-as

使用 fake-as 可以将本地真实的 AS 编号隐藏&#xff0c;其他 AS 内的对等体在指定本端对等体所在的AS 编号时&#xff0c;应该设置成这个伪AS 编号。 这是实验拓扑&#xff0c;IBGP EBGP 邻居都使用物理接口来建立 基本配置&#xff1a; R1: sys sysname R1 int loo0 ip add…

带libc源码gdb动态调试(导入glibc库使得可执行文件动态调试时可看见调用库函数源码)

文章目录 查看源码是否编译时有-g调试信息和符号表在 gdb 中加载 debug 文件/符号表将 debug 文件放入 ".debug" 文件夹通过 gdb 命令 set debug-file-directory directories GCC的gcc和g区别指定gcc/g&#xff0c;glibc的版本进行编译指定gcc/g的版本指定glibc的和l…

小电影网站上线之nginx配置不带www域名301重定向到www域名+接入腾讯云安全防护edgeone

背景 写了个电影网站&#xff08;纯粹搞着玩的&#xff09;&#xff0c;准备买个域名然后上线&#xff0c;但是看日志经常被一些恶意IP进行攻击&#xff0c;这里准备接入腾讯云的安全以及加速产品edgeone&#xff0c;记录下当时的步骤。 一、nginx配置重定向以及日志格式 ng…

【数据分析】Excel中使用VBA进行宏编程

目录 0 准备工作1 VBA简介1.1 Excel VBA应用程序的构成1.2 事件驱动1.3 宏1.3.1 创建宏1.3.2 宏安全 2 VBA基础2.1 注释2.2 数据类型2.2.1 基本数据类型2.2.2 枚举类型2.2.3 用户自定义数据类型 2.2 变量2.3 常量2.4 运算符2.5 程序结构2.6 过程2.7 函数 3 Excel应用程序开发流…

【Apollo CyberRT】源码分析之 “component” 模块

代码位置 apollo/cyber/component 功能 在自动驾驶系统中&#xff0c;模块&#xff08;如感知、定位、控制系统等&#xff09;在 Cyber ​​RT 下以 Component 的形式存在。不同 Component 之间通过 Channel 进行通信。Component 概念不仅解耦了模块&#xff0c;还为将模块拆…

实现图片分块化(使用einops库)

背景介绍 在进行机器学习的模型训练任务的时候&#xff0c;针对图像数据集的处理&#xff0c;常常会对数据集进行分块的操作&#xff1b;具体到模型结构中&#xff0c;在ViT框架中&#xff0c;把每一个图像看作是一个的patch&#xff0c;每一个patch可以当作是一个NLP领域的一…

mac上搭建hbase伪集群

1. 前言 之前我们已经搭建过了 hbase单点环境&#xff0c;(单机版搭建参见&#xff1a; https://blog.csdn.net/a15835774652/article/details/135569456) 但是 为了模拟一把集群环境 我们还是尝试搭建一个伪集群版 2. 环境准备 jdk环境 1.8hdfs &#xff08;hadoop环境 可选…

Android双指缩放ScaleGestureDetector检测放大因子大图移动到双指中心点ImageView区域中心,Kotlin(2)

Android双指缩放ScaleGestureDetector检测放大因子大图移动到双指中心点ImageView区域中心&#xff0c;Kotlin&#xff08;2&#xff09; 在 Android ScaleGestureDetector检测双指缩放Bitmap基于Matrix动画移动到双指捏合中心点ImageView区域中心&#xff0c;Kotlin-CSDN博客 …

程序员开发要素—Java篇

这是个预留板块&#xff0c;打算写一写作为程序员的基本要素和技术。主要包含基本工具&#xff0c;基础知识&#xff0c;基础插件应用&#xff0c;环境搭建等内容。 具体内容后续补充完整&#xff0c;Ps&#xff1a;请假申请已提交https://blog.csdn.net/qq_18237141/article/…

跟着小德学C++之TOTP

嗨&#xff0c;大家好&#xff0c;我是出生在达纳苏斯的一名德鲁伊&#xff0c;我是要立志成为海贼王&#xff0c;啊不&#xff0c;是立志成为科学家的德鲁伊。最近&#xff0c;我发现我们所处的世界是一个虚拟的世界&#xff0c;并由此开始&#xff0c;我展开了对我们这个世界…