【C语言】预处理(预编译)(C语言完结篇)
一、预定义符号
前面我们学习了C语言的编译和链接。
在C语言中设置了一些预定义符号,其可以直接使用,预定义符号也是在预处理期间处理的。
如下:

可以看到上面的预定义符号,其都有两个短下划线,要注意的是,这两个短下滑一定不能少,而且这两个下划线之间是没有空的,其是挨在一起的。
下面我们来详细了解这几个预定义符号,
1、_ _FILE_ _代表当前进行边编译的源文件,在打印时,要使用占位符%s,其不单单会打印文件名,还会将文件的完整路径打印出来。
2、_ _LINE_ _代表出现这个预定义符号的行号,例如这个预定义的符号出现在第6行,那么其就为6,那么其打印就使用%d占位符。
3、_ _DATE_ _代表文件被编译的日期,打印的时候使用%s占位符。
4、_ _TLME_ _代表文件被编译的具体时间,具体到时分秒,打印的时候也是使用占位符%s。
5、_ _STDC_ _就和编译文件的编译器有联系了,当前我们的编译器要是支持ANSI C的标准,那么其就会被定义,其值为1,反之则报错。
下面我们使用这几个预定义符号:
下面我们运行看看:
我们可以看到上面的运行结果,首先_ _FILE_ _其将我们这个文件的完整路径打印出来了。
然后_ _LINE_ _其就会标识当前所在的行数,然后我们打印出来的就是8。
_ _DATE_ _代表是文件编译的时间。
_ _TLME_ _其表示具体的时间,精确到时分秒。
那么为啥我们上面不使用第五个预定义符号呢?
这是因为我们不知道当前的编译器是否支持ANSI C,要是不支持那么程序就会报错了,所以我们下面单独使用其看看我们当前的环境是否支持:

可以看到我们写代码的时候编译器就已经报错了,下面我们运行看看其错误:

二、#define定义常量
这个关键字我们在前面的学习也已经遇到过了,下面我们来详细学习。
其定义常量的语法如下:
![]()
那么M就是我们定义的常量的名字,100是我们定义的常量的值。
我们可以使用#define来定义各种类型的常量,我们使用其定义常量,对于常量的名字有个约定,就是对名字最好使用全部大写。
这个定义常量,其本质上是替换,其在预处理后,会将程序中的M替换成100。
所以我们使用#define定义常量的时候,末尾不要加分号,因为其会将这个分号也当成常量替换进我们的程序。
如下:

可以看到此时的编译器已经报错了。
所以为了避免一些错误,我们使用#define来定义一个常量的时候,末尾不要加分号;
三、#define定义宏
#define机制中有个规定,允许将参数替换到文本中去,这种实现通常称为宏或定义宏。
如下:

其中parament-list是由一个逗号隔开的符号表,它们可能出现在stuf中。
要注意的是:参数列表的左边括号一定要和名字紧紧相邻,不要空格,不然参数就会被解释成stuf的部分了。
下面我们通过一个例子来理解:

我们发现上面宏的形式和我们的函数有点像,前面部分就相当于我们的函数名,括号里面的就相当于函数参数,不过其没有限制数据的类型,最后面的部分就相当于我们的函数体。
其实际上是替换的规则,比如SQUARE(5),那么预处理后就会将这个语句转化为5*5。
注意:
那个括号要个宏的名字紧紧挨在一起,不然可能会导致这部分被认为是后面的部分。
还有就是宏是将括号里面的x直接替换到后面的x,那么我们看看下面的写法:

我们首先是想求a+1的平方的,然后我们就传了个a+1进去替换,那么在这个语句中实际上是这样的:
a+1*a+1;
那么我们将a=5代入求得结果应该为11;那么就不是我们想要得到的结果了。

我们可以看到上面没有得到我们想要的结果是因为运算符号的优先级的问题,那么我们可以使用一个括号来解决这个问题:

这样是不是就没有问题了呢?
我们看看下面的代码:
我们大家有一开始想着的是对这个数的两倍再乘10吧,但是这个代码的结果并非所愿。
运行结果:
那么我们将其替换进去看看这个式子实际上是咋样的:
10*5+5,可以发现其也是因为运算的优先级导致的问题,此时我们是希望这个宏的结果先算出来,然后再乘10,那么我们就使用括号,改变其运算的顺序。
如下:
那么此时就得到我们想要的结果了。
四、带有副作用的宏参数
以前我们使用宏的时候可能就不知道宏参数有副作用,现在我们来好好学习一下这个知识。
带有副作用的宏参数,也就是我们在使用这个宏的时候,其可能会带来一些问题,导致我们意料之外的事情发生,不过这个副作用主要是后面的内容的部分导致的,其就是表达式求值的时候出现的永久性效果。
下面我们通过一个例子看看:

我们看上面的两个宏,在后面的内容上其表达的意思好像是一样的,但是x++,是会导致x的值发生永久改变的,然后x+1这个就对x的值没有影响。
下面我们再通过一个例子来看:

那么这个代码的运行情况是咋样的呢?我们首先就是a和b先进入这个宏,然后这个宏的语句完成后,然后a++和b++,那么此时我们认为的结果是a为6,b为3,ret为5。那么我们运行看其结果:

可以看到其结果并不是这样,那么我们具体分析一下吧,我们将进替换进去:
((a++)>(b++)?(a++):(b++));
我们将其替换进去后可以看到为啥了,首先是第一个表达式,a和b进行比大小后,进行++,然后这个结果是1,那么就执行a++,导致a进行了两次++,就使得a的值为7了,然后就进行了一次++,那么其结果就是3了,还有就是对于ret的值,其在比完大小后a此时是6,然后整个表达式的结果是第二个语句,其此时是后置++,那么就是6。
那么ret就是6了。
所以我们在使用宏的时候,最好不要使用++和--操作,不过,我们在使用宏的时候,可以先替换看看其是否可以实现我们需要达到的效果。
五、宏替换规则
我们在程序中使用宏和#define符号的时候,需要涉及到下面的几个步骤:
1、在调用宏的时候,首先会对参数进行检查,看其是否包含任何由#define定义的符号,如果有那么其会首先被替换掉。
2、替换文本随后被插入到程序中原来文本的位置,不做任何的更改,而对于宏,参数名被它们的值所替换。
3、最后,再次对结果文件进行扫描,看其是否包含任何由#define定义的符号,如果是,那么就会在进行上述的操作,直到其没有包含#define定义的符号。
我们使用宏还需要注意下面几点:
1、宏参数和#define定义可以出现其他#define定义的符号,但是对于宏,就不能出现递归的情况。
2、当预处理搜索#define定义的符号的时候,字符串常量的内容并不被搜索。
六、宏和函数的对比

相关文章:
【C语言】预处理(预编译)(C语言完结篇)
一、预定义符号 前面我们学习了C语言的编译和链接。 在C语言中设置了一些预定义符号,其可以直接使用,预定义符号也是在预处理期间处理的。 如下: 可以看到上面的预定义符号,其都有两个短下划线,要注意的是ÿ…...
关于聊天室数据库建表
首先了解一下外键 一、外键的本质 定义:外键是某个表中的字段(或字段组合),其值必须与另一张表的主键值相匹配。 核心作用:强制数据一致性,维护表间关系。 二、外键的核心用途…...
Java 面试总结
1. Java 并发volatile 问题代码 class NumberDemo { //private AtomicInteger count = new AtomicInteger(0);private volatile int count = 0;public void add() {this.count++;}public int getCount() {return this.count;} }public class ThreadDemo {public static void m…...
基于 OpenHarmony 5.0 的星闪轻量型设备应用开发-Ch1 开发环境搭建
写在前面: 文本所写的工程创建均是基于 HH-SPARK-WS63 星闪无线模组。 此篇是系列文章《基于 OpenHarmony5.0 的星闪轻量型设备应用开发》的第 1 章。 1.1 介绍 HH-SPARK-WS63 星闪无线模组(以下简称 WS63)是由润和软件推出的基于海思 WS63V…...
离线安装 nvidia-docker2(nvidia-container-toolkit)
很多时候大家都有用docker使用gpu的需求,但是因为网络等原因不是那么好用,这里留了一个给ubuntu的安装包,网络好的话也提供了在线安装方式 安装 nvidia-docker2 1 离线安装 (推荐) unzip解压后进入目录 dpkg -i *.d…...
H.264 NVMPI解码性能优化策略
H.264 NVMPI解码性能优化策略 1. 硬件与驱动配置 JetPack版本匹配:确保NVIDIA Jetson设备的JetPack SDK版本与CUDA驱动兼容,避免因驱动不匹配导致硬件解码性能下降8。显存分配优化:调整FFmpeg的-hwaccel_device参数指定GPU…...
2025年道路运输安全员证考试主要内容
道路运输安全员考试主要针对从事道路运输企业安全生产管理的人员,考核其对道路运输安全法律法规、安全管理知识及应急处置能力的掌握。 考试内容 1. 理论知识部分 安全生产法律法规 国家安全生产方针政策(如“安全第一、预防为主、综合治理”&#x…...
10、nRF52xx蓝牙学习(GPIOTE事件模式中断组件)
由于驱动组件库是可以直接调用的,那么编程者的任务就只有编写主函数 main。 #include <stdbool.h> #include "nrf.h" #include "nrf_drv_gpiote.h" #include "app_error.h" #include "boards.h" /* #ifdef BSP_BUTTO…...
第7篇:Linux程序访问控制FPGA端LEDR<五>
Q:如何设计.c程序代码实现FPGA端外设LEDR流水灯? A:在DE1-SoC开发板上实现的流水灯效果:一次只点亮一个红色LED,初始状态为向左移动直至点亮LEDR9,然后改变移动的方向为向右直至点亮LEDR0,以此…...
类名与协议名相同,开发中应该避免吗?
在 Objective-C 开发中,协议与实现类之间的命名关系非常重要。虽然语言允许协议名和类名相同,但从可读性和维护性等角度出发,这种做法并不推荐。本文通过一个典型示例展开分析,并提供更合理的命名建议。 一、示例 在某项目中&…...
linux下io操作详细解析
在 Linux 系统下,IO(输入/输出)操作是程序与外部设备(如文件、网络等)交互的重要方式。Linux 提供了丰富的系统调用和库函数来支持各种 IO 操作。以下是对 Linux 下 IO 操作的详细解析,包括文件 IO、网络 I…...
Unity 实现伤害跳字
核心组件: Dotween TextMeshPro 过程轨迹如下图: 代码如下: using System.Collections; using System.Collections.Generic; using DG.Tweening; using TMPro; using UnityEngine; using UnityEngine.Pool;public class …...
Java集合框架:核心接口与关系全解析
精心整理了最新的面试资料和简历模板,有需要的可以自行获取 点击前往百度网盘获取 点击前往夸克网盘获取 一、集合框架概述 Java集合框架(Java Collections Framework, JCF)是Java中用于存储、操作和管理数据集合的核心工具库。它提供了一套…...
008二分答案+贪心判断——算法备赛
二分答案贪心判断 有些问题,从已知信息推出答案,细节太多,过程繁杂,不易解答。 从猜答案出发,贪心地判断该答案是否合法是个不错的思路,这要求所有可能的答案是单调的(例:x满足条件…...
计算机视觉与深度学习 | 视觉SLAM学习思路总结与视觉SLAM发展历程(1986年至2025年)
视觉SLAM(Simultaneous Localization and Mapping,同时定位与建图)是计算机视觉和机器人领域的重要研究方向,涉及数学、几何、优化、传感器融合等多学科知识。以下是学习视觉SLAM的系统化思路总结,适合从入门到进阶的学习路径:视觉SLAM学习思路总结 一、基础准备 数学基…...
衣橱管理助手系统(衣服推荐系统)(springboot+ssm+vue+mysql)含运行文档
衣橱管理助手系统(衣服推荐系统)(springbootssmvuemysql)含运行文档 该系统名为衣橱管理助手,是一个衣物搭配管理系统,主要功能包括衣物档案管理、衣物搭配推荐、搭配收藏以及套装智能推荐。用户可以通过系统进行衣物的搭配和收藏管理,系统提…...
学习笔记四——Rust 函数通俗入门
🦀 Rust 函数通俗入门 📘 Rust 是一门语法精炼但设计严谨的系统级语言。本文围绕函数这一主线,带你真正搞懂 Rust 最关键的语法思想,包括表达式驱动、闭包捕获、Trait 限制、生命周期标注与所有权规则,每遇到一个新概念…...
【场景应用3】audio_classification:音频分类的微调
1 引言 本笔记展示了如何对多语种预训练的语音模型进行微调,以实现自动语音识别(Automatic Speech Recognition)。 本笔记旨在使用SUPERB数据集中的关键词检测子集,并且可以使用任何来自模型库(Model Hub)的语音模型检查点,只要该模型有一个包含序列分类头(Sequence …...
文件上传做题记录
1,[SWPUCTF 2021 新生赛]easyupload2.0 直接上传php 再试一下phtml 用蚁剑连发现连不上 那就只要命令执行了 2,[SWPUCTF 2021 新生赛]easyupload1.0 当然,直接上传一个php是不行的 phtml也不行,看下是不是前端验证,…...
【Pandas】pandas DataFrame to_numpy
Pandas2.2 DataFrame Conversion 方法描述DataFrame.astype(dtype[, copy, errors])用于将 DataFrame 中的数据转换为指定的数据类型DataFrame.convert_dtypes([infer_objects, …])用于将 DataFrame 中的数据类型转换为更合适的类型DataFrame.infer_objects([copy])用于尝试…...
Vue环境搭建:vue+idea
目录 第一章、Vue环境搭建:安装node2.1)node的下载2.2)配置node的环境变量2.3)常见的npm命令 第二章、使用idea创建vue工程2.1)在IDEA中设置国内镜像2.2)在IDEA中进行脚手架安装2.3)在IDEA中创建…...
ECMAScript 7~10 新特性
ECMAScript 7 新特性 ECMAScript 6 新特性(一) ECMAScript 6 新特性(二) ECMAScript 7~10 新特性(本文) 1. 数组方法 Array.prototype.includes() 用来检测数组中是否包含指定元素,返回布尔值&…...
银河麒麟v10(arm架构)部署Embedding模型bge-m3【简单版本】
硬件 服务器配置:鲲鹏2 * 920(32c) 4 * Atlas300I duo卡 参考文章 https://www.hiascend.com/developer/ascendhub/detail/07a016975cc341f3a5ae131f2b52399d 鲲鹏昇腾Atlas300Iduo部署Embedding模型和Rerank模型并连接Dify(自…...
Manifold-IJ 2022.1.21 版本解析:IntelliJ IDEA 的 Java 增强插件指南
Manifold-IJ-2022.1.21 可能是 IntelliJ IDEA 的一个插件或相关版本,特别是与 Manifold 这个增强 Java 开发体验的框架相关的组件。 很多时候没有网络环境,而又需要这个插件。 Manifold-IJ 2022.1.21下载:https://pan.quark.cn/s/ad907344c…...
轻量级碎片化笔记memos本地NAS部署与跨平台跨网络同步笔记实战
文章目录 前言1. 使用Docker部署memos2. 注册账号与简单操作演示3. 安装cpolar内网穿透4. 创建公网地址5. 创建固定公网地址 推荐 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。 点击跳转到网站 前言…...
【C++算法】54.链表_合并 K 个升序链表
文章目录 题目链接:题目描述:解法C 算法代码: 题目链接: 23. 合并 K 个升序链表 题目描述: 解法 解法一:暴力解法 每个链表的平均长度为n,有k个链表,时间复杂度O(nk^2) 合并两个有序…...
EG8200Mini-104边缘计算网关!聚焦IEC104协议的工业数据转换与远程运维平台
在工业自动化和信息化融合不断深化的背景下,现场设备的数据采集与协议转换能力对系统集成效率与运维成本产生着直接影响。EG8200Mini-104边缘计算网关正是基于此需求场景设计,具备IEC104主从站双向支持能力,并配套远程运维与多网络接入方案&a…...
python多线程+异步编程让你的程序运行更快
多线程简介 多线程是Python中实现并发编程的重要方式之一,它允许程序在同一时间内执行多个任务。在某些环境中使用多线程可以加快我们代码的执行速度,例如我们通过爬虫获得了一个图片的url数组,但是如果我们一个一个存储很明显会非常缓慢&…...
各种场景的ARP攻击描述笔记(超详细)
1、ARP报文限速 上一章我们说过ARP报文也是需要上送CPU进行处理的协议报文,如果设备对收到的大量ARP报文全部进行处理,可能导致CPU负荷过重而无法处理其他业务。因此,在处理之前需要对ARP报文进行限速,以保护CPU资源。 1.根据源MAC地址或源IP地址进行ARP限速 当设备检测到某一…...
Java 实现 List<String> 与 String 互转
在 Java 开发过程中,有时需要将 List<String> 转为 String 存储,后续使用时再还原回去。此时就需要 Java 实现 List<String> 与 String 互转。以下是一种互转方式。 采用如下工具包实现。 <dependency><groupId>org.apache.com…...
