当前位置: 首页 > 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】冯.诺依曼体系结构与操作系统进程概念什么是进程?进程是什么?我们打开任务管理器可以看到有…...

[STM32U3] 【STM32U385RG 测评】+ PWM调节控制LED

在厂家提供的例程中,提供了多个PWM通道输出固定占空比的示例,但缺少改变占空比的介绍。为此,作了一下自动改变占空比和按键改变占空比的尝试。这采用的是以PWM通道1输出脉冲来控制外挂LED模块的亮度,通道1的输出引脚为PA0&#xf…...

避坑指南:从ADS导入DXF到Altium Designer时,如何解决封装丢失和铺铜失败的常见问题

从ADS到Altium Designer的工程迁移:封装与铺铜问题的深度解决方案 在射频与微波电路设计领域,工程师常常面临一个典型困境:如何在ADS(Advanced Design System)中完成高频仿真后,将设计无缝迁移到Altium Des…...

Apache RocketMQ 5.0 架构解析:如何基于云原生架构支撑多元化场景

本文将从技术角度了解 RocketMQ 的云原生架构,了解 RocketMQ 如何基于一套统一的架构支撑多元化的场景。 文章主要包含三部分内容。首先介绍 RocketMQ 5.0 的核心概念和架构概览;然后从集群角度出发,从宏观视角学习 RocketMQ 的管控链路、数…...

用51单片机+DAC0832做个信号发生器:5种波形可调,附Proteus仿真和Keil源码

51单片机DAC0832信号发生器实战指南:从硬件搭建到波形调频 在电子设计领域,信号发生器是基础但极其重要的工具。传统商用设备往往价格昂贵且功能固定,而基于51单片机和DAC0832的自制信号发生器不仅成本低廉,还能根据需求灵活定制。…...

【NotebookLM提示工程黄金标准】:基于137个真实项目验证的4类任务Prompt评分矩阵

更多请点击: https://intelliparadigm.com 第一章:NotebookLM提示工程研究 NotebookLM 是 Google 推出的基于用户自有文档进行深度理解与对话的 AI 工具,其核心能力高度依赖高质量的提示(Prompt)设计。与通用大模型不…...

Spring AI 技术架构深度解析:聊天模型、工具调用与 MCP 协议

摘要:本文从分层架构切入,精简拆解 SpringAI 核心设计思想,详解聊天模型统一抽象、注解式工具调用实战逻辑,同时解析主流模型上下文协议 MCP 在 SpringAI 中的落地价值,助力 Java 开发者快速搭建企业级生成式 AI 应用。…...

现代Web全栈技术栈实践:从Next.js到PostgreSQL的标准化开发方案

1. 项目概述:一个现代Web应用的技术栈实践最近在技术社区里看到一个挺有意思的项目,叫stack-wuh/x.wuh.site。光看这个名字,可能有点摸不着头脑,但拆解一下就能明白,这本质上是一个关于“技术栈”的实践项目。stack-wu…...

6种专业计时模式!OBS高级计时器插件让你的直播时间管理精准到秒

6种专业计时模式!OBS高级计时器插件让你的直播时间管理精准到秒 【免费下载链接】obs-advanced-timer 项目地址: https://gitcode.com/gh_mirrors/ob/obs-advanced-timer 还在为直播时间控制而烦恼吗?OBS Advanced Timer计时器插件就是你的救星&…...

在自动化部署流程中集成 TaoToken 大模型 API 调用

🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 在自动化部署流程中集成 TaoToken 大模型 API 调用 将大模型能力融入自动化部署流程,正成为提升 DevOps 效率的新范式。…...

法学博士论文降重+溯源双突破:NotebookLM文献脉络追踪功能(实测引用准确率98.6%,超人工校验)

更多请点击: https://intelliparadigm.com 第一章:NotebookLM法学研究辅助的范式变革 传统法学研究长期依赖人工检索、逐条比对判例与法条、手工整理文献脉络,知识关联深度受限于研究者个体经验与时间成本。NotebookLM 的引入,标…...