【C】编译与链接

  在本文章里面,我们讲会讲解C语言程序是如何从我们写的代码一步步变成计算机可以执行的二进制指令,并最终执行的。C语言程序运行主要包括两大步骤 -- 编译和链接,接下来我们就来一一讲解。


目录

1  翻译环境和运行环境

2  翻译环境 

 1) 预处理(预编译)

2) 编译

(1) 词法分析

(2) 语法分析

(3) 语义分析 

3) 汇编 

4) 链接


1  翻译环境和运行环境

  在ANSI C(标准C)的任何一种实现里面,都会包含两个不同的环境:

  1) 翻译环境:会将源代码转变为可执行的二进制的机器指令。

  2) 运行环境:用于执行实际的代码。

  两个环境之间的关系可以用图片来描述一下:

用语言简单改过一下就是,各种源文件通过翻译环境中的编译和链接两步,会将我们写的C代码转变成机器能够执行的二进制指令,然后生成可执行程序(.exe为后缀的文件),在运行环境中就可以运行了。

   所以可执行程序中存放的都是二进制指令,如果直接用记事本打开会看到是一堆乱码:


2  翻译环境 

  翻译环境主要由编译和链接两步组成,而编译又由预处理(预编译)、编译、汇编三个过程,所以翻译环境也可以说成是由预处理、编译、汇编、链接四小部分组成

  一个C语言的项目一般会由多个源文件共同构成,每一个源文件会先经过编译器(在vs中为cl.exe)生成对应的目标文件(Windows环境下后缀为.obj,Linux环境下后缀为.o),然后在经过链接器(vs中为link.exe)把各个目标文件和链接库(运行时库(支持程序运行的基本函数的集合)和第三方库)一起链接为可执行程序

 1) 预处理(预编译)

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

  预处理阶段主要会处理一些以 # 开头的预处理指令,具体规则如下: 

预处理(预编译)处理规则
1将所有的 #define 删除,并展开所有的宏定义
2处理所有的预编译指令,如 #if 、#endif、#ifdef、#elif、#else 等等
3处理 #include 预编译指令,将包含的头文件的内容插入到预编译指令的位置
4删除所有注释
5添加行号和文件名标识,方便后续编译器生成调试信息等
6

保留所有的 #pragma 的编译器指令,编译器后续使用

  第6条我们曾在结构体内存对齐中曾经使用过,如:

//修改默认对齐数为1
#pragma pack(1)


//还原为默认对齐数
#pragma pack()

2) 编译

  编译的主要作用将C语言代码转变为汇编代码,会对文件进行一系列的:词法分析,语法分析,语义分析及优化,生成相应的汇编代码文件

  如以下的这个代码:

arr[index] = (index + 5) * (3 * 8); 

(1) 词法分析

  将原代码程序输入扫描器,然后由扫描器进行词法分析,将代码中的字符分割成一系列的记号(关键词,标识符,特殊字符等)。上述代码会在扫描器中会分割成以下记号:
  

(2) 语法分析

  经过词法分析之后,语法分析器会对产生的记号进行语法分析,产生语法树(以表达式为结点的树):

(3) 语义分析 

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

  语义标识后的语法树如图所示:

3) 汇编 

  经过了预处理和编译之后,就到了汇编阶段,在该阶段会用汇编器将汇编代码转变为机器执行的指令,也就是二进制指令,不做指令优化。

  经过了以上三个阶段,就生成了目标文件。

4) 链接

  链接会将一堆文件链接在一起,生成一个可执行程序。

  链接过程主要包括:地址和空间分配,符号决议和重定位等。其实链接解决的是一个项目中多文件、多模块之间的相互调用问题。

比如:

//add.c
int Add(int x, int y)
{
  return x + y;
}


//test.c
#include<stdio.h>

//extern声明外部函数
extern int Add(int, int);

int main()
{
  int a = Add(3, 5);
  printf("%d\n", a);

  return 0;
}

在add.c源文件中有一个Add函数。而在test.c源文件中,用extern关键字声明了外部函数并在main函数中使用了Add函数。

  其实在链接的过程中,每一个源文件中分别会对函数和全局变量来生成一个符号表,这个符号表里面存储了函数和全局变量的地址,对于定义了的函数和全局变量会在符号表中存储真正的地址,而对于文件中没有定义只是声明的函数和全局变量的地址会先在符号表中存储一个无效的地址,然后链接的时候,会将符号表合并,在其他模块里面寻找真正定义过相同函数和全局变量的地址,来修正文件中引用到该函数的地址,若符号表中仍存在无效地址,咋会报链接错误。

  比如在以上例子中,假设test.c 生成的符号表为:

test.c 文件的符号表
Add函数0x00000000(无效地址)
main函数0x1187f3c0

add.c 文件的符号表
Add函数0x12f2d7c4

  在链接时,会将两个符号表合并生成一个新的符号表:

合成的符号表
Add函数0x12f2d7c4
main函数0x1187f3c0

  再比如以下这个例子:

//add.c
int add(int x, int y)
{
  return x + y;
}


//test.c
#include<stdio.h>

extern int Add(int x, int y);

int main()
{
  int ret = Add(3, 5);
  
  return 0;
}
test.c 文件的符号表
Add函数0x00000000(无效地址)
main函数0x1187f3c0

add.c 文件的符号表
add函数0x12f2d7c4

合成的符号表
Add函数0x00000000(无效地址)
main函数0x1187f3c0
add函数0x12f2d7c4

合成的符号表中出现了无效地址,所以运行时会报链接错误:

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

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

相关文章

如何设计一个注册中心?以Zookeeper为例

这是小卷对分布式系统架构学习的第8篇文章&#xff0c;在写第2篇文章已经讲过服务发现了&#xff0c;现在就从组件工作原理入手&#xff0c;讲讲注册中心 以下是面试题&#xff1a; 某团面试官&#xff1a;你来说说怎么设计一个注册中心&#xff1f; 我&#xff1a;注册中心嘛&…

Vision Transformer模型详解(附pytorch实现)

写在前面 最近&#xff0c;我在学习Transformer模型在图像领域的应用。图像处理任务一直以来都是深度学习领域的重要研究方向&#xff0c;而传统的卷积神经网络已在许多任务中取得了显著的成绩。然而&#xff0c;近年来&#xff0c;Transformer模型由于其在自然语言处理中的成…

vue实现虚拟列表滚动

<template> <div class"cont"> //box 视图区域Y轴滚动 滚动的是box盒子 滚动条显示的也是因为box<div class"box">//itemBox。 一个空白的盒子 计算高度为所有数据的高度 固定每一条数据高度为50px<div class"itemBox" :st…

Vue指令(下)

Vue指令(下) 参考文献&#xff1a; Vue的快速上手 Vue指令上 文章目录 Vue指令(下)v-bindv-bind小案例v-forv-for小案例v-for中的keyv-model 结语 博客主页: He guolin-CSDN博客 关注我一起学习&#xff0c;一起进步&#xff0c;一起探索编程的无限可能吧&#xff01;让我们…

初学者关于对机器学习的理解

一、机器学习&#xff1a; 1、概念&#xff1a;是指从有限的观测数据中学习(或“猜 测”)出具有一般性的规律&#xff0c;并利用这些规律对未知数据进行预测的方法.机器学 习是人工智能的一个重要分支&#xff0c;并逐渐成为推动人工智能发展的关键因素。 2、使用机器学习模型…

Vue篇-05

5 vuex 5.1 vuex是什么 概念:专门在 Vue 中实现集中式状态(数据)管理的一个Vue 插件&#xff0c;对 vue 应用中多个组件的共享状态进行集中式的管理(读/写)&#xff0c;也是一种组件间通信的方式&#xff0c;且适用于任意组件间通信。Github 地址: https://github.com/vuejs/…

Vue3(elementPlus) el-table替换/隐藏行箭头,点击整行展开

element文档链接&#xff1a; https://element-plus.org/zh-CN/component/form.html 一、el-table表格行展开关闭箭头替换成加减号 注&#xff1a;Vue3在样式中修改箭头图标无效&#xff0c;可能我设置不对&#xff0c;欢迎各位来交流指导 转变思路&#xff1a;隐藏箭头&…

opencv的NLM去噪算法

NLM&#xff08;Non-Local Means&#xff09;去噪算法是一种基于图像块&#xff08;patch&#xff09;相似性的去噪方法。其基本原理是&#xff1a; 图像块相似性&#xff1a;算法首先定义了一个搜索窗口&#xff08;search window&#xff09;&#xff0c;然后在该窗口内寻找…

NineData云原生智能数据管理平台新功能发布|2024年12月版

本月发布 7 项更新&#xff0c;其中重点发布 2 项、功能优化 5 项。 重点发布 数据库 Devops - Oracle 非表对象支持可视化创建与管理 Oracle 非表对象&#xff0c;包括视图&#xff08;View&#xff09;、包&#xff08;Package&#xff09;、存储过程&#xff08;Procedur…

计算机网络 —— 网络编程(TCP)

计算机网络 —— 网络编程&#xff08;TCP&#xff09; TCP和UDP的区别TCP (Transmission Control Protocol)UDP (User Datagram Protocol) 前期准备listen &#xff08;服务端&#xff09;函数原型返回值使用示例注意事项 accpect &#xff08;服务端&#xff09;函数原型返回…

eNSP之家----ACL实验入门实例详解(Access Control List访问控制列表)(重要重要重要的事说三遍)

ACL实验&#xff08;Access Control List访问控制列表&#xff09;是一种基于包过滤的访问控制技术&#xff0c;它可以根据设定的条件对接口上的数据包进行过滤&#xff0c;允许其通过或丢弃。访问控制列表被广泛地应用于路由器和三层交换机。 准备工作 在eNSP里面部署设备&a…

PySide6基于QSlider实现QDoubleSlider

我在写小工具的时候&#xff0c;需要一个支持小数的滑动条。 我QSpinBox都找到了QDoubleSpinBox&#xff0c;QSlider愣是没找到对应的东西。 网上有好多对QSlider封装实现QDoubleSlider的文章。 似乎Qt真的没有这个东西&#xff0c;需要我们自行实现。 于是我也封装了一个&…

即插即用,无缝集成各种模型,港科大蚂蚁等发布Edicho:图像编辑一致性最新成果!

文章链接&#xff1a;https://arxiv.org/pdf/2412.21079 项目链接&#xff1a;https://ezioby.github.io/edicho/ 亮点直击 显式对应性引导一致性编辑&#xff1a;通过将显式图像对应性融入扩散模型的去噪过程&#xff0c;改进自注意力机制与分类器自由引导&#xff08;CFG&…

福建双色荷花提取颜色

提取指定颜色 HSV双色荷花代码验证 参照《OpenCV图像处理技术》 HSV 要用HSV的色调、饱和度和亮度来提取指定颜色。 双色荷花 农林大学金山校区观音湖 代码 import cv2 import numpy as npimgcv2.imread("./sucai6/hua.jpg") cv2.imshow("SRC",img) h…

关于重构一点简单想法

关于重构一点简单想法 当前工作的组内&#xff0c;由于业务开启的时间正好处于集团php-》go技术栈全面迁移的时间点&#xff0c;组内语言技术栈存在&#xff1a;php、go两套。 因此需求开发过程中通常要考虑两套技术栈的逻辑&#xff0c;一些基础的逻辑也没有办法复用。 在这…

【操作系统】课程 7设备管理 同步测练 章节测验

7.1知识点导图 它详细地展示了I/O系统的层次结构、I/O硬件和软件的组成以及它们的功能。下面是对图中内容的文字整理&#xff1a; I/O设备分类 按使用特性分类 输入设备&#xff1a;键盘、鼠标等输出设备&#xff1a;打印机、绘图仪等交互式设备&#xff1a;显示器等 按传输速率…

用 Python 绘制可爱的招财猫

✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连✨ ​​​​​ ​​​​​​​​​ ​​​​ 招财猫&#xff0c;也被称为“幸运猫”&#xff0c;是一种象征财富和好运的吉祥物&#xff0c;经常…

【Vue.js 组件化】高效组件管理与自动化实践指南

文章目录 摘要引言组件命名规范与组织结构命名规范目录组织 依赖管理工具自动化组件文档生成构建自动引入和文档生成的组件化体系代码结构自动引入组件配置使用 Storybook 展示组件文档自动生成 代码详解QA 环节总结参考资料 摘要 在现代前端开发中&#xff0c;组件化管理是 V…

4.5 在C++节点中使用参数

本节沿用之前4.3 节小海龟控制例子。 4.5.1 参数声明与设置 打开src/demo_cpp_service/src/turtle_control.cpp文件 添加测试代码 this->declare_parameter("k",1.0);this->declare_parameter("max_speed",1.0);this->get_parameter("k&q…

Java agent

‌ Java Agent是一种特殊的Java程序&#xff0c;它可以在JVM启动时或运行时动态加载&#xff0c;用于监控和修改其他Java应用程序的行为‌。通过Java Agent&#xff0c;开发者可以在不修改目标应用程序源码的情况下&#xff0c;动态地插入功能&#xff0c;如性能分析、日志记录…