预处理详解(上)

news2024/11/28 22:54:06

1. 预定义符号


C语言设置了一些预定义符号,可以直接使用,预定义符号也是在预处理期间处理的。

__FILE__ //进行编译的源文件
__LINE__ //文件当前的行号
__DATE__ //文件被编译的日期
__TIME__ //文件被编译的时间
__STDC__ //如果编译器遵循ANSIC,其值为1,否则未定义
举个例子:

2. #define定义常量 

基本语法:

 举个例子:

我们定义了一个MAX它的值为5。

思考:在define定义标识符的时候,要不要在最后加上 ; 呢?其实我们所定义的特殊符号,在预处理阶段就会进行替换。如果我们加上“;”的话,就会出现替换时有两个“;”,就会导致语法错误。

上述代码中就是举个例子,大家理解一下,在vs上不好将预处理时的代码弄出来观察,大家可以在gcc上试试。我们在预处理阶段MAX就会被替换为5。

 3. #define定义宏

#define机制包括了一个规定,允许把参数替换到文本中,这种实现通常称为宏(macro)或定义宏
(definemacro)。

下面是宏的申明方式:

 其中的 parament-list 是一个由逗号隔开的符号表,它们可能出现在stuff中。
注意:
参数列表的左括号必须与name紧邻,如果两者之间有任何空白存在,参数列表就会被解释为stuff的一部分。

我们定义一个加法宏:

这个宏接收两个参数 x,y .如果在上述声明之后, 你将3,5,给ADD就会直接给你计算,其实替换后

ret=3+5;在这里没有什么问题我们再来看一个例子。

为啥这里结果会是8呢?其实在预处理阶段是直接进行替换,是不会进行计算的。那样的话我们在替换后就会得到3+1*5就会等于8了,那样怎样解决这个问题呢?其实我们只需要给参数加上括号就好了,让它们成为一个整体。

 注意:

所以用于对数值表达式进行求值的宏定义都应该用这种方式加上括号,避免在使用宏时由于参数中的操作符或邻近操作符之间不可预料的相互作用。

4. 带有副作用的宏参数

当宏参数在宏的定义中出现超过一次的时候,如果参数带有副作用,那么你在使用这个宏的时候就可能出现危险,导致不可预测的后果。副作用就是表达式求值的时候出现的永久性效果。

如我们在定义宏的时候想得到参数的加1后的数字我们可以定义x+1,也可以定义x++,但是x++就会产生副作用,因为我们在得到参数加1的结果时,参数的值也得到了永久性的改变。

我们来举一个例子:

那这串代码的结果会是多少呢?我们来思考一下:预处理阶段直接进行替换成:((x++)>(y++)?(x++):(y++)),这个时候我们先比较大小,发现不成立,所以结果为y++,但是在比较的时候就已经加1了,所以此时的y为9,然后又是后置++,所以先将值赋给z然后再加1,变为10,而a就在比较式进行了一次++,所以值为6,我们发现在比较大小后,a和b的值都改变了,这就是证明了带副作用的宏。那是不是呢?我们来验证一下:

5. 宏替换的规则


在程序中扩展#define定义符号和宏时,需要涉及几个步骤:
1. 在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号。如果是,它们首先被替换。
2. 替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值所替换。
3. 最后,再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上述处理过程。
注意:
1. 宏参数和#define定义中可以出现其他#define定义的符号。但是对于宏,不能出现递归。
2. 当预处理器搜索#define定义的符号的时候,字符串常量的内容并不被搜索。

6. 宏和函数的对比

优势:宏通常被应用于执行简单的运算

1.用于调用函数和从函数返回的代码可能比实际执行这个小型计算工作所需要的时间更多。所以宏比函数在程序的规模和速度方面更胜一筹。
2. 更为重要的是函数的参数必须声明为特定的类型。所以函数只能在类型合适的表达式上使用。反之这个宏怎可以适用于整形、长整型、浮点型等可以用于 > 来比较的类型。宏是类型无关的。

劣势:

1. 每次使用宏的时候,一份宏定义的代码将插入到程序中。除非宏比较短,否则可能大幅度增加程序的长度。
2. 宏是没法调试的。
3. 宏由于类型无关,也就不够严谨。
4. 宏可能会带来运算符优先级的问题,导致程容易出现错。

宏有时候可以做函数做不到的事情。比如:宏的参数可以出现类型,但是函数做不到。

宏和函数的一个对比 :

谢谢

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

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

相关文章

Linux--目录结构

目录 一、Linux的目录结构二、常用的目录介绍 一、Linux的目录结构 Linux的目录结构是一个树型结构。 Windos 系统可以拥有多个盘符,如C盘,D盘,E盘。 Linux 木有盘符这个概念,只有一个根目录 /(相当于文件夹)&#xf…

掌握C语言文件操作:从入门到精通的完整指南!

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ 🎈🎈养成好习惯,先赞后看哦~🎈🎈 所属专栏:C语言学习 贝蒂的主页:Betty‘s blog 1. 什么是文件 文件其实是指一组相关数据的有序集合。这个数据集有一个名称&a…

MPLAB V8.92 printf

Compile error “A heap is required, but has not been specified” Set printf function #if 0 //for UART1 int fputc(int ch, FILE *f) { IFS1bits.U2TXIF 0; // if (runConfig.printOn 1) { // usart_data_transmit(USART0, (uint8_t)ch); U2TXREG ch; // while (RESE…

二分查找算法及其简单应用(C语言实现)

目录 二分查找算法介绍 二分查找算法的简单应用 二分查找算法介绍 二分查找算法,指在一组有序的数组内查找数值,查找的数值与查找范围内的中间数值进行比较,如果比中间数值小,则在原范围内的左侧范围内重复与该范围内的中间数值…

RK3568笔记十四:yolov8pose部署

若该文为原创文章,转载请注明原文出处。 本篇参考山水无移大佬文章,并成功部署了yolov8pose在RK3568板子上,这里记录下全过程。 在此特感谢所有分享的大佬,底部附大佬的链接。 一、环境 1、平台:rk3568 2、开发板: …

微信小程序 民宿预订租赁系统uniApp

通过山青水磨APP办理租房相关业务,线上解决预定、退订的业务,旅客在使用时更加灵活,实现了快速找房,在线沟通、便捷租赁等操作,除此以外,还能帮助旅客获取周边资讯、当地特色活动服务,提升旅客的…

C++,stl,函数对象,谓词,内建函数对象

目录 1.函数对象使用 2.谓词 1.一元谓词 2.二元谓词 3.内建函数对象 1.算术仿函数 2.关系仿函数 3.逻辑仿函数 1.函数对象使用 #include<bits/stdc.h> using namespace std;class add { public:int operator()(int v1,int v2){return v1 v2;} };class print { p…

origin技巧

origin技巧 1.去掉白边2.曲线平滑3.合并多层图例3.图例换方向 1.去掉白边 ctrlu 2.曲线平滑 3.合并多层图例 3.图例换方向 图例右键 “图例” 水平排布修改图例字&#xff1a;双击图例修改 https://blog.csdn.net/m0_47746156/article/details/121295151 https://blog.csdn.…

【网站项目】023实验室耗材管理系统

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

BUGKU-WEB GET

题目描述 没有提示&#xff0c;就一个get&#xff0c;启动场景看看&#xff1a; 解题思路 显然是PHP语言解读分析代码吧写出你的payload 相关工具 略 解题步骤 进入场景分析代码 $what$_GET[what]; echo $what; if($whatflag) echo flag{****};前两句&#xff1a;使用get…

《区块链公链数据分析简易速速上手小册》第3章:区块链数据结构(2024 最新版)

文章目录 3.1 区块和交易的结构3.1.1 基础知识3.1.2 重点案例&#xff1a;构建简单的区块链3.1.3 拓展案例 1&#xff1a;验证交易签名生成密钥对签名交易验证签名完整的交易签名与验证演示 3.1.4 拓展案例 2&#xff1a;监听和解析区块链事件代币合约示例&#xff08;Solidity…

HarmonyOS 通过getInspectorByKey获取指定元素高宽等属性

例如 这里 我们有这样一个组件 Entry Component struct Dom {build() {Column() {Row() {Circle({ width: 200, height: 200 }).fill(#20101010)}.id(ES)}.width(100%).height(100%)} }这里 我们就写了个很基本的组件结构 然后 我们写了个 Circle 组件 定义了宽高 然后 如果我…

消息中间件面试篇

目录 消息中间件 RabbitMQ 消息不丢失 生产者确认机制 消息持久化 交换机持久化 队列持久化 消息持久化 消费者确认 消息重复消费 出现的场景 解决方案 每条消息设置一个唯一的标识id 幂等方案&#xff1a;【 分布式锁、数据库锁&#xff08;悲观锁、乐观锁&#…

VMware虚拟机安装openEuler系统(二)(2024)

下面我们进行openEuler系统的一些简单配置。 1. 开启openEuler系统 在VMware Workstation Pro虚拟机软件中找到安装好的openEuler操作系统虚拟机并开启。 等待开启。 2. 安装配置 进入后选择第一个“Install openEuler 20.03-LTS”。 3. 选择系统语言 为虚拟机设置系统语言…

【lesson53】线程控制

文章目录 线程控制 线程控制 线程创建 代码&#xff1a; 运行代码&#xff1a; 强调一点&#xff0c;线程和进程不一样&#xff0c;进程有父进程的概念&#xff0c;但在线程组里面&#xff0c;所有的线程都是对等关系。 错误检查: 传统的一些函数是&#xff0c;成功返回0&…

【Java】零基础蓝桥杯算法学习——二分查找

算法模板一: // 数组arr的区间[0,left-1]满足arr[i]<k,[left,n-1]满足arr[i]>k;Scanner scan new Scanner(System.in);int[] arr {1,2,3,4,5};int left 0,right arr.length-1;int k scan.nextInt();while(left<right) {//leftright时退出循环int mid (leftrigh…

【Linux 02】权限基本概念

文章目录 &#x1f308; Ⅰ 权限概念&#x1f308; Ⅱ 权限管理1. 文件访问者分类 (角色)2. 文件类型和访问权限 (事物属性)3. 文件权限值表示方法 &#x1f308; Ⅲ 权限修改1. chmod 设置文件访问权限2. chown 修改文件拥有者3. chgrp 修改文件或目录的所属组 &#x1f308; …

【ArcGIS Pro二次开发】(79):符号系统_CIMUniqueValueRenderer

CIMUniqueValueRenderer是ArcGIS Pro SDK中的一个类&#xff0c;用于创建唯一值渲染器&#xff08;Unique Value Renderer&#xff09;。 在ArcGIS Pro中长这样&#xff1a; 通过对CIMUniqueValueRenderer的操作&#xff0c;可以对符号系统进行更改&#xff0c;实现很多功能。…

Matplotlib Figure与Axes速成:核心技能一网打尽

Matplotlib Figure与Axes速成&#xff1a;核心技能一网打尽 &#x1f335;文章目录&#x1f335; &#x1f333;引言&#x1f333;&#x1f333; 一、Figure&#xff08;图形&#xff09;&#x1f333;&#x1f341;1. 创建Figure&#x1f341;&#x1f341;2. 添加Axes&#…

【教学类-47-01】20240206UIBOT+IDM下载儿童古诗+修改文件名

背景需求&#xff1a; 去年12月&#xff0c;我去了其他幼儿园参观&#xff0c;这是一个传统文化德育教育特色的学校&#xff0c;在“古典集市”展示活动中&#xff0c;小班中班大班孩子共同现场念诵《元日》《静夜思》包含了演唱版本和儿歌念诵版本。 我马上也要当班主任了&a…