当前位置: 首页 > news >正文

编译链接和预处理

    🌺在本次的博客当中我们可以一起来学习一下C语言的编译链接以及预处理的知识。

    🌺要谈到C语言的编译和链接就肯定得从我们C语言程序运行的时候所产生的诸多的文件类型了。我们正常情况下编辑书写代码的文件为 .c 文件,我们的 .c 文件通过遍历和链接步骤之后生成可以执行的 .exe 文件。我们的编译和链接步骤当中的编译步骤又可以细分为预编译,编译,汇编三个步骤。我们可以通过一张图片进行感受编译和链接的用法。

83cbdd821f344d14adb64be48f0262a1.png

    🌺在编译的步骤当中我们的.c文件首先会经过预处理生成一个.i文件,之后我们的.i文件又会经过编译生成我们的.s文件,最后我们的.s文件通过汇编操作最终生成一个.o文件。到此为止我们的编译的步骤才算到此为止。由于我们在编译的过程中生成的一系列文件不同,所以我们每个阶段所进行的操作也各不相同。首先在我们的预编译阶段主要会进行如下三个操作:1.#include 头文件的包含 2.#define 定义符号的替换和删除 3.注释的删除 在预编译阶段我们进行的都是文本的替换操作 并不会对代码进行过多的更改。

    🌺下一个步骤叫做编译,在这个步骤当中编译器将C语言代码翻译成了汇编代码。在这一步骤我们的编译器会对代码进行语法分析,词法分析,语义分析,以及符号汇总。在我们的符号汇总阶段汇总的符号会形成一张符号表。最后一个阶段就是我们的汇编的阶段。我们通常情况下我们在上一阶段转换完成的汇编代码翻译成二进制的指令。并存放在我们的目标文件当中。

    🌺当我们的编译阶段完成之后就来到了我们的链接阶段了。在这一阶段我们会进行的操作分为两步:1.合并段表 2.符号表的合并和重定位 当我们完成之后就会产生一个 .exe 文件。我们不同的文件之间的函数的使用会在这一阶段进行相互连接。

    🌺在完成上述的步骤之后我们程序的编译链接的步骤也就完成了。接下来我们在来认识一下我们的预处理操作:我们在上面的讲解当中说到过,我们头文件的包含,宏定义,注释的删除等操作都是在这一步骤当中完成的。我们介绍预处理操作的时候主要针对于我们的宏定义进行的。

    🌺我们最常见的宏定义是使用我们的 #define 进行定义的。假如我们在我们的程序当中定义了一个宏常量,那么我们在程序进行预处理的时候会将我们的关键字直接替换成我们对应的值。举一个简单的代码进行理解:

    🌺就像是我们所执行的代码一样。通过内部分析我们可以知道我们的程序会在预处理的阶段直接将我们的NUM 替换成为我们定义的常量的数字12。除了使用宏定义定义一个常量之外我们呢还可以使用宏定义定义一个表达式,利用宏定义的替换操作达到函数的表达效果。在举一个简单的例子:     🌺看到这里相信你肯定会觉得宏定义很方便对吧。确实,宏定义使用起来确实很方便,但是我们使用宏定义的时候得格外小心。因为我们的宏定义不会进行语法的检查,只会进行无脑的替换,即使我们在宏定义当中的语法是错误的我们的程序也会直接替换到正式的代码当中,对编写代码造成困扰。还有就是我们对于复杂的宏定义的替换难以估计其输出的值。举一个简单的例子:

     🌺按照我们正常的代码的编写的逻辑我们上面的代码应该可以正常的运行但是实际上却不是,这是因为我们在if当中使用了宏定义替换,而我们的宏定义替换已经定义了一个分号,而我们在if语句当中又重新加入了一个分号,使得我们下面的if无法进行特定的匹配。我们可以试着将我们宏定义当中的分号去掉,或者给我们if语句当中的语句加一个括号进行一下检验。     🌺上面仅仅是编译的错误,较多的使用宏定义可能还会造成无法预知的错误,比如下图的代码:

    🌺按照我们正常的逻辑来分析代码:我们的ADD宏定义中应该得到的结果为8,之后乘3得到的结果应该是24。但是我们实际得到的结果却是18,这是因为我们的宏定义并不会主动给我们的定义内容加上括号。所以我们程序替换之后应进行的计算为:3+5*3 会计算3*5得到15 之后加上3。得到我们最终的答案18。要想解决上面的问题我们可以增加括号。更改之后的代码如下:

    🌺 我们使用宏定义还可能会产生对后面的代码产生副作用。所谓的副作用指的是我们在使用 ++ 自增的语句的时候对本身变量产生的影响。

    🌺看到上面的代码可能大家会很疑惑,为什么会由上面的结果呢?我们就来进行分析:首先我们调用宏定义的时候传入的参数为x++,y++。第一次使用的时候将我们的x更改为6,y更改为9,之后我们就会继续调用(b)的步骤,输出9。我们的y又会自增一变成10。所以就产生了上图所示的代码的运行结果。如果我们使用函数进行定义这一项功能的话就不需要考虑的这么复杂。     🌺我们的自增操作只会在函数的调用的时候进行一次,并不会在函数当中带入a++和b++而是带入一个值,这样就是我们代码的运行逻辑更加清晰。你可能会想:那什么时候使用宏定义什么时候使用函数呢?

    🌺当我们的语句比较短的时候我们就可以使用我们的宏定义进行操作。因为我们的宏定义代码量比较短,我们使用函数的话,还会进行函数栈帧的创建。在我们创建函数所花费的时间要远远长于我们代码运行计算的时间。所以对于我们逻辑比较清晰,代码量比较短的代码来说我们使用宏定义程序运行的速度要快于我们的函数。我们可以通过这一特点进行宏定义和函数的选择。

    🌺接下来我们再来认识一下我们的条件编译的内容。当我们在编写程序的时候在前面定义了一个宏定义之后我们之后的所有的操作都会自动进行宏替换,但是假如我们在使用完之后不想再让这个宏定义发挥功能了应该怎么办呢?这时候我们可以使用 #undef 命令进行宏定义的取消。沃尔玛呢仅需要将我们之前定义好的宏常量在我们的undef当中重新定义一遍即可。执行代码如下:

     🌺 对于我们最常见的条件编译主要为 #if...#elif...#else...#endif或者 #if defined。在这些条件编译当中我们可以进行代码的选择性编译,针对我们的宏定义是否进行定义而控制我们的编译的内容。举一个简单的例子来说:

     🌺我们所要在选择编译当中所要进行的操作结构如上图(上图中的为便于理解的伪代码,我们可以根据伪代码进行实际代码的完善)我们实际的代码的编写如下:

    🌺但我们在前面定义了一个宏常量的话就可以对于这个宏常量进行判断,并输出特定的代码。其结构和我们的条件分支语句的思想大致相同。同样的我们也可以使用我们的 #if defined进行判断。我们的 #if defiend  的作用同样是对于我们之前定义的变量进行判断。如果定义了的话就执行相应的指令,没有的话就直接跳过。所示的代码如下:

    🌺就像是我们上面所展示的示例效果那样。

    🌺那么此上就是本次博客的全部内容了,感谢您的观看。 

相关文章:

编译链接和预处理

🌺在本次的博客当中我们可以一起来学习一下C语言的编译链接以及预处理的知识。 🌺要谈到C语言的编译和链接就肯定得从我们C语言程序运行的时候所产生的诸多的文件类型了。我们正常情况下编辑书写代码的文件为 .c 文件,我们的 .c 文件通过遍历…...

基于sprinmgboot实现实习管理系统的设计【源码+论文】

基于sprinmgboot实习管理系统的设计与实现演示摘要 随着信息化时代的到来,管理系统都趋向于智能化、系统化,实习管理也不例外,但目前国内仍都使用人工管理,市场规模越来越大,同时信息量也越来越庞大,人工管…...

动态规划入门

前言:首先,什么是动态规划? 动态规划算法通常用于求解具有某种最优性质的问题。在这类问题中,可能会有许多可行解。每一个解都对应于一个值,我们希望找到具有最优值的解。动态规划算法与分治法类似,其基本思…...

day26 SpringBootWeb案例(二)

目录 SpringBootWeb案例 1. 新增员工 1.1 需求 1.2 开发 1.3 测试 2. 文件上传 2.1 简介 2.2 本地存储 2.3 阿里云OSS 3. 配置文件 3.1 Value 3.2 yml配置 3.3 ConfigurationProperties 4. 修改员工 4.1 需求 4.2 查询回显 4.3 保存修改 SpringBootWeb案例 前…...

力扣-《剑指offer》-哈希表-刷题笔记

目录 第一题:03.数组中重复的数字 第二题:39.数组中出现次数超过一半的数字 第三题:50.第一个只出现一次的字符 第四题:53. (0-n-1)中缺失的数字 第一题:03.数组中重复的数字 我的答案&…...

【SpringBoot】| 邮箱发送验证码,你会了吗?

目录🦁 题外话🦁 提前准备2.1 配置邮箱第三方登录2.1.1 点击设置——账户2.1.2 开启POP3/SMTP服务2.2 添加依赖2.3 yaml配置🦁 进入主题🦁 测试使用🦁 尾声3.1 安利一个生成验证码的工具类3.1.1 添加依赖3.1.2 编写配置…...

Linux系统安装部署及配置Grafana

TOC 用于 UI 展示 wget https://dl.grafana.com/oss/release/grafana-8.0.3-1.x86_64.rpm1 安装 grafana 1.1 下载安装 wget https://dl.grafana.com/oss/release/grafana-8.0.3-1.x86_64.rpmsudo yum install grafana-8.0.3-1.x86_64.rpm1.2 启动&状态查看 sudo syst…...

Python3 入门教程||Python3 输入和输出||Python3 File 方法

Python3 输入和输出 在前面几个章节中,我们其实已经接触了 Python 的输入输出的功能。本章节我们将具体介绍 Python 的输入输出。 输出格式美化 Python 两种输出值的方式: 表达式语句和 print() 函数。(第三种方式是使用文件对象的 write() 方法; 标准输出文件可以…...

有效的字母异位词(力扣刷题)

给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。 示例 1: 输入: s "anagram", t "nagaram" 输出: true 示例 2: 输入: s "rat", t "car" 输出: false 说明: 你可以假设字符串只包含小写字母。 …...

73、介绍下 HashMap 的底层数据结构

73、介绍下 HashMap 的底层数据结构 我们现在用的都是 JDK 1.8,底层是由“数组链表红黑树”组成,如下图,而在 JDK 1.8 之前是由“数组链表”组成。 1.Hash Hash叫做”散列表“,就是把任意长度的输入,通过散列算法&am…...

系统集成路由器OSPF动态、综合路由配置

实验任务:动态路由协议RIP、OSPF协议的内容和特点动态路由RIP、OSPF实验,建立拓扑pc1>>R1>>R2>>R3>>pc2,使pc1与pc2能相互通信,并配置PC端静默接口。熟悉配置vlan间路由技术:多层交换机虚拟接…...

【力扣周赛 338】

6354. K 件物品的最大和 - 力扣(Leetcode)袋子中装有一些物品,每个物品上都标记着数字 1、0或 -1。给你四个非负整数 numOnes、numZeros、numNegOnes和 k。袋子最初包含:numOnes 件标记为 1 的物品。numZeroes 件标记为 0 的物品。…...

大数据Flink进阶(八):Apache Flink架构介绍

Apache Flink架构介绍 一、Flink组件栈 在Flink的整个软件架构体系中,同样遵循这分层的架构设计理念,在降低系统耦合度的同时,也为上层用户构建Flink应用提供了丰富且友好的接口。...

Mars3d项目启动上的一些坑

前言 最近新入职了一家公司,公司新开了有个未来城市的项目,需要用到3D城市建模,公司老总选了Mars3d作为前端框架,项目分给我了,又是一个全新的领域,开搞吧! 下面是自己遇到的几个小问题&#x…...

通俗易懂【Springboot】 单文件下载和批量下载(多个文件合成一个压缩包下载)

文章目录一.单文件下载1.简单理解文件下载2.单文件下载的具体代码实现3.测试4.单文件下载整体代码二.多文件批量下载(多个文件合成一个压缩包下载)1.多文件下载的实现方式,这里使用了ZipOutputStream2.具体代码实现3.测试4.文件批量下载&…...

CnOpenData中国行政区划shp数据

一、数据简介 中国行政区划数据是重要的基础地理信息数据,目前不同来源的全国行政区划数据非常多,但能够开放获取的高质量行政区域数据少之又少。基于此,锐多宝的地理空间制作一套2013-2023年可开放获取的高质量行政区划数据。该套数据以2022…...

GPT-4零失误通关大厂模拟面试,offer拿到手软?与AGI首次接触

来源: FoxyearMeta “GPT-4可被视作AGI (通用人工智能)的早期版本。” 如若从他人口中说出,或许是无稽之谈—— 但是由微软雷蒙德研究院机器学习理论组负责人万引大神Sbastien Bubeck与2023新视野数学奖得主Ronen Eldan、2023新晋斯隆研究奖得…...

Hardhat 环境搭建及教程示例

一.安装node.js curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash nvm install 18 nvm use 18 nvm alias default 18 npm install npm --global # Upgrade npm to the latest version 二. 安装hardhat 2.1 创建hardhat安装目录 mkdir hard…...

复杂链表的复制-剑指Offer35-java

一、题目描述 请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null。 示例 1: 输入:head [[7,null],[13,…...

【Linux】进程理解与学习Ⅰ-进程概念

环境:centos7.6,腾讯云服务器Linux文章都放在了专栏:【Linux】欢迎支持订阅🌹相关文章推荐:【Linux】冯.诺依曼体系结构与操作系统进程概念什么是进程?进程是什么?我们打开任务管理器可以看到有…...

WebKitX ActiveX 6.0 X86 Crack

WebKitX ActiveX将 Chromium Embedded Framework (CEF3) 包装到一个进程外的 ActiveX 组件中,以便与 OLE/COM 语言一起使用。Chromium Embedded Framework 封装了 WebKit Blink HTML5 Renderer 和 Google V8 JavaScript Engine。这是一个用于商业用途的生产级稳定组…...

开源项目:数据库表结构生成文档工具

目录 一、软件介绍 二、技术框架 三、功能介绍 四、代码展示 1、获取数据库信息部分代码 2、导出Html文档代码 五、运行效果 六、项目开源地址 一、软件介绍 今天给大家分享我自己编写的数据库表结构文档生成工具,方便大家在实际开发当中,可以很方便导出…...

spring的两种拦截器HandlerIntercepter和MethodIntercepter

介绍 Spring有两种拦截器提供给我们使用,一种是HandlerIntercepter,另一种是MethodIntercepter。这两种的来源不同,实现方式也不同,具体的下面来看一下。 HandlerIntercepter 来源 来源于spring-webmvc包 HandlerIntercepter拦…...

初级算法-字符串

主要记录算法和数据结构学习笔记,新的一年更上一层楼! 初级算法-字符串一、反转字符串二、反转字符串(二)三、替换空格四、翻转字符串里的单词五、左旋转字符串六、实现 strStr()七、重复的子字符串字符串中元素只能是字符String…...

华为OD机试题 - 寻找目标字符串(JavaScript)| 机考必刷

更多题库,搜索引擎搜 梦想橡皮擦华为OD 👑👑👑 更多华为OD题库,搜 梦想橡皮擦 华为OD 👑👑👑 更多华为机考题库,搜 梦想橡皮擦华为OD 👑👑👑 最近更新的博客 华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为…...

删除Terminating状态的namespace:cattle-system

这里以cattle-system为例!执行删除命令后namespace(也是用其他k8s object)仍然存在,首先执行 kubectl edit namespace cattle-system 查看是否存在spec.finalizers: kubernetes,如: spec: finalizers:…...

MiniOB 并发B+树实现解析

MiniOB 是 OceanBase 联合华中科技大学推出的一款用于教学的小型数据库系统,希望能够帮助数据库爱好者系统性的学习数据库原理与实战。 B 树介绍 B 树是传统数据库中常见的索引数据结构,比如MySQL、PostgreSQL都实现了B树索引。B 树是一个平衡多叉树&am…...

SpringCloud负载均衡服务调用——Ribbon

Ribbon 本专栏学习内容来自尚硅谷周阳老师的视频 有兴趣的小伙伴可以点击视频地址观看 简介 Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡的工具。 简单的说,Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算…...

各种邮箱服务软件对比

1.宝塔邮局管理器 特点:简单易用,可视化操作,小白也能搞,还有备份功能,一般足够用了 缺点:稳定性真是差,隔三差五的不能收发.没有接口,不能任意修改邮箱密码,只能管理员修改 注意要点:一定要开启ssl,否则有些邮箱给你发邮件你收不到 建议:不要入坑.坏了之后没法修复,哭都没地方…...

相机单独标定的实现过程[autoware标定]、tmp文件的查看方式

安装了autoware1.13和calibration标定包,发现实现相机单独标定的过程较为坎坷,参考了一些博主的方法,发现下面的过程更加适合自己,做个笔记。 1安装标定箱(与calibration标定包的安装并不冲突) 标定工具箱…...