预处理详解

 1.预定义符号

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

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

关于这几串预定义符号怎么用下面我给出例子我们来看一下:

#include <stdio.h>
{printf("%s\n",__FILE__);printf("%s\n",__DATE__);printf("%s\n",__TIME__);printf("%d\n",__LINE__);return 0;
}

我们可以根据 ,这些预定义符号的说明来理解他们的作用。我们创建的test.c文件他的源文件文件当前的行号文件被编译的日期和时间都被打印出来了。

那这个__STDC__这个符号是什么意思呢?我们再来看一下:

 

但是我们换成gcc的编译器可以得到下面的情况:

 

 这就说明gcc是支持ANSIC

 2.#define定义常量

#define有两个作用:

1.#define定义符号(常量)

2.#define定义宏

那我们看一下#define怎么定义常量的,下面给出个模型:

 #define name stuff

先是#define ,然后加上符号名后面在是它的内容

我们接下来看一下怎么用#define定义常量

 

看到了没有,最终关键字都会被内容替换掉。 

下面我在给出几个例子我们来看一下:

#define MAX 1000\\定义一个MAX,他的值是一千,这就是一个符号的定义
#define reg register   //为register这个关键字,创建一个简短的名字
#define do_forever for(;;)    //用更形象的符号来替换一种实现
#define CASE break;case    //再写case语句的时候自动把break写上
//如果定义的stuff过长,可以分成几行写,除了最后一行外,每行的后面都加一个反斜杠(续行符)
#define DEBUG_PRINT printf("file:%s\tline:%d\t \ date:%s\ttime:%s\n" ,\ __FILE__,__LINE__ ,      \__DATE__,__TIME__ )

 我们抽出一个#define定义的常量来看一下

#define do_forever for(;;) 
//我们可以看到这里的for(;;)初始化部分,调整部分,判断部分都可以省略掉
//但是判断部分如果省略掉不写的话,就意味着判断条件恒为真,就会造成死循环。

我们要考虑一个问题就是关于define定义标识符的时候,要不要考虑在最后加上;

就像这样:

#define MAX 1000;
#define MAX 1000

建议不要加上 ; ,这样容易导致问题。

比如下面的场景:

#define MAX 1000//如果不加分号的话MAX被替换下来就是1000
int main()
{
int a = MAX;//int a = 1000;就是这样
}#define MAX 1000;//如果加分号的话MAX被替换下来就是1000;
int main()
{
int a = MAX;//int a = 1000;;就像是这样,这就成了两条语句了,这显然不正确
}

 下面我在给说一个非常明显的错误

# define MAX 1000;//如果我们在最后带上了分号
int main()
{int m = 0;if(1)m = MAX;//当这里的MAX被替换了之后就成这样了:m = 1000;;这时就成为了两条语句了,但是我们都知道如果没有大括号的时候,if后面只能有一条语句,所以这里会出现语法错误。elsem = -1;
return 0;
}

3.#define定义宏

#define 机制包括了一个规定,允许把参数替换到文本中,这种实现通常称为宏(macro)定义宏(define macro)
下面是宏的申明方式: 

#define name( parament-list ) stuff

其中的 parament-list 是一个由逗号隔开的符号表,它们可能出现在stuff中。

这里我们需要注意的是:

参数列表的左括号必须与name紧邻,如果两者之间有任何空白存在,参数列表就会被解释为stuff的一部分。就类似于#define定义常量

下面关于宏我们来举上一个例子:实现一个宏,求一个数的平方

 

那这串代码怎么进行的?   就像上面说的:允许把参数替换到文本中

结合上面这串代码就是把x替换成a

 

结果就是这样。 

但是这样写会有一种错误就是这样的

 

按理来说a+1是6结果应该等于36,但是为什么是十一呢?

所以我们可以知道:宏的参数不会进行计算,只是单纯的替换,预处理之后就是这样:

 

就想这样只进行了替换,所以结果是十一。 

这里还有一个宏定义:

 

#define DOUBLE(x) (x) + (x)

定义中我们使用了括号,想避免之前的问题,但是这个宏可能会出现新的错误。

int a = 5;
printf("%d\n" ,10 * DOUBLE(a));

那这串代码打印出来会是什么呢?我们感觉会是100,但是结果就是55,为什么呢?

因为乘法运算先于宏的加法,所以出现了55。那怎么办呢?

这个问题的解决办法是在宏定义表达式两边加上一对括号就可以了。就想这样:

#define DOUBLE(x) ( ( x ) + ( x ) )

提示:

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

4。带有副作用的宏参数 

举一个很简单的例子就是下面的这串代码: 

这个就是带有副作用的,因为在++b之后虽然a已经成为11了,但是b的结果也变了。 

MAX宏可以证明具有副作用的参数所引起的问题:

写一个宏,求两个数的较大值

#define MAX(a, b) ( (a) > (b) ? (a) : (b) )
int main()
{int a = 3;int b = 5;int m = MAX(a,b);printf("%d\n",m);return 0;
}

这串代码结果就是5,这串代码没有副作用,那我们把他变一下: 

#define MAX(a, b) ( (a) > (b) ? (a) : (b) )
int main()
{int a = 3;int b = 5;int m = MAX(a++,b++);
//替换之后就是这样的int m = ( (a++) > (b++) ? (a++) : (b++) )后置++,先用在++
//首先先是a++和b++的比较但是是先比较在++。3大于5这个是错的,比完之后a为4,b为6,因为是错的所以?后面的a++是不用计算的,之后就是b++,所以m就是6,之后b在加1,b就成为了7                       printf("m = %d\n",m);printf("a = %d\n",a);printf("b = %d\n",b);
//所以结果就是m = 6  a = 4  b = 7
return 0;
}

 所以结果就是m = 6  a = 4  b = 7

这就是带有副作用的宏参数。 

 

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在Clion使用CubeMX Stm32的步骤

Step1 准备软件&#xff0c;安装环境&#xff1a; 1. cubemx v6.5.0&#xff08;可以兼容以前版本的project&#xff09; https://www.st.com.cn/zh/development-tools/stm32cubemx.html STM32CubeMX 默认安装目录, 6.5版本可以兼容老版本 C:\Program Files\STMicroelectroni…

SpringMVC常见的注解

一、Spring MVC Spring Web MVC是基于ServletAPI构建的原始web 框架&#xff0c;一开始就包含在Spring 框架中&#xff0c;通常被称为“Spring MVC”。 1.MVC 是什么&#xff1f; MVC(Model、View、Controller&#xff09;是软件工程中的一种软件架构设计模型。它把软件系统分…

Vision Transformer论文阅读笔记

目录 An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale -- Vision Transformer摘要Introduction—简介RELATED WORK—相关工作METHOD—方法VISION TRANSFORMER (VIT)—视觉Transformer(ViT) 分析与评估PRE-TRAINING DATA REQUIREMENTS—预训练数据…

战略流程-麦肯锡企业数字化业务变革成熟度评估模型及案例深度解析

一、企业变革成熟度评估模型 企业变革成熟度诊断模型是一种评估工具&#xff0c;用于全面扫描和评估企业在变革转型过程中的能力水平。该模型通过一系列量化指标和定性分析&#xff0c;对企业在不同变革领域的成熟度进行评分&#xff0c;从而帮助企业识别在变革过程中的优势和…

llm学习-3(向量数据库的使用)

1&#xff1a;数据读取和加载 接着上面的常规操作 加载环境变量---》获取所有路径---》加载文档---》切分文档 代码如下&#xff1a; import os from dotenv import load_dotenv, find_dotenvload_dotenv(find_dotenv()) # 获取folder_path下所有文件路径&#xff0c;储存在…

mysql数据库自动备份

crond cron 实现定时执行 安装 yum install crond启动 service crond start查看状态 service crond status执行 crontab xx.cron查看任务列表 crontab -l删除所有任务 crontab -r 示例&#xff1a;每分钟写入 Good morning 到 mine.cron [rootecs-f1dd-0001 fztmp]# echo ‘* …

什么是 API 代理?

API 代理就像是您的计算机和互联网上特殊服务之间的中间人。它有点像集翻译、保安和信使于一体。 什么是 API 代理&#xff1f; API 代理就像是您和在线服务之间的中间人。当您的计算机需要从某个特殊的在线服务 (API) 获得某些东西时&#xff0c;API 代理会确保一切顺利进行…

使用 llamaIndex 快速实现智能体

AI 智能体就是可以根据当前环境进行推理&#xff0c;并根据处理结果进行下一步的操作。简单来说 AI 智能体可以与外界环境进行交互&#xff0c;并根据结果执行更复杂的操作。本文将通过llamaIndex 实现一个简单的 Agent 实时获取数据&#xff0c;由于大模型是通过静态数据进行训…

BAS(入侵与攻击模拟)正在替代红队测试?

之前经常会被用户问到&#xff0c;漏扫、渗透和红队红的区别是啥&#xff1f; 传统的漏扫、渗透和红蓝对抗&#xff0c;可以看到工具化的漏洞不可靠&#xff0c;人工的成本就高。怎么找到一个漏洞可信度又高&#xff0c;成本又低的&#xff0c;就诞生了BAS。 抛开漏扫&#xf…

CTO透露GPT-5内幕,OpenAI 以36亿美元收购数据库初创公司

目录 01 GPT-5 02 OpenAI收购Rockset 2.1 谁是Rockset&#xff1f; 2.2 OpenAI的目的是什么&#xff1f; 01 GPT-5 虽然GPT-4的视频通话功能尚未全面推广&#xff0c;但OpenAI的CTO已经对即将到来的GPT-5给出了新的暗示。 不久前&#xff0c;Mira回到母校达特茅斯工程学…

数据结构——跳表Skip List

本文对跳表的定义、实现、应用等进行简单总结。 一、 介绍 1.定义 跳表&#xff08;Skip List&#xff09;&#xff1a;是一种概率性数据结构&#xff0c;由William Pugh在1990年提出&#xff0c;主要用于在有序的元素集合上进行快速的搜索、插入和删除操作。跳表的效率与平衡…

MyBatis3(动态SQL 常用的动态SQL 元素 映射器注解 基本注解 结果映射注解)

目录 一、动态SQL 常用的动态SQL 元素 二、if元素 三、choose 、when 、otherwise 元素 四、trim 、where 、set 元素 trim&#xff08;不常用&#xff09; where set 五、foreach 元素 六、bind 元素 #{} ${} 区别 示例完整代码 七、映射器注解 八、基本注解 …

远程登录WINDOWS10,提示你的凭据不工作

1&#xff1a;想通过远程桌面登录WINDOWS10输入用户名和密码后&#xff0c;出现下面的提示。 2&#xff1a;登录WINDOWS10&#xff0c;在运行中输入gpedit.msc 3&#xff1a;本地组策略编辑器窗口中&#xff0c;依次展开&#xff0c;计算机配置 ---> 管理模版---> 系统--…

【LLM 论文】Self-Refine:使用 feedback 迭代修正 LLM 的 output

论文&#xff1a;Self-Refine: Iterative Refinement with Self-Feedback ⭐⭐⭐⭐ CMU, NeurIPS 2023, arXiv:2303.17651 Code: https://selfrefine.info/ 论文速读 本文提出了 Self-Refine 的 prompt 策略&#xff0c;可以在无需额外训练的情况下&#xff0c;在下游任务上产…

DMA学习笔记

参考文章 https://blog.csdn.net/as480133937/article/details/104927922 DMA简介 DMA&#xff0c;全称Direct Memory Access&#xff0c;即直接存储器访问。DMAC 即 DMA 控制器&#xff0c;提供了一种硬件的数据传输方式&#xff0c;无需 CPU 的介入&#xff0c;可以处理外…

【LeetCode】九、双指针算法:环形链表检测 + 救生艇

文章目录 1、双指针算法1.1 对撞双指针1.2 快慢双指针 2、leetcode141&#xff1a;环形链表3、leetcode881&#xff1a;救生艇 1、双指针算法 用两个指针来共同解决一个问题&#xff1a; 1.1 对撞双指针 比如先有一个有序的数组array int[] array {1, 4, 5, 7, 9}先要找两个…

小程序-<web-view>嵌套H5页面支付功能

背景&#xff1a;小程序未发布前&#xff0c;公司使用vue框架搭建了管理系统&#xff0c;为了减少开发成本&#xff0c;微信提供了web-view来帮助已有系统能在小程序上发布&#xff0c;详见web-view | 微信开放文档。因公司一直未打通嵌套H5小程序的支付功能&#xff0c;导致用…

3D模型如何在力控组态中打开?---模大狮模型网

在展览3D模型设计行业中&#xff0c;力控组态是一个关键的技术应用。通过适当的力控组态&#xff0c;可以实现模型的互动性和真实感&#xff0c;提升展览效果和用户体验。本文将探讨如何在力控组态中打开和应用3D模型&#xff0c;从而达到更加生动和引人入胜的展示效果。 一、了…

WPF/C#:BusinessLayerValidation

BusinessLayerValidation介绍 BusinessLayerValidation&#xff0c;即业务层验证&#xff0c;是指在软件应用程序的业务逻辑层&#xff08;Business Layer&#xff09;中执行的验证过程。业务逻辑层是应用程序架构中的一个关键部分&#xff0c;负责处理与业务规则和逻辑相关的…

MySql Innodb 索引有哪些与详解

概述 对于MYSQL的INNODB存储引擎的索引&#xff0c;大家是不陌生的&#xff0c;都能想到是 B树结构&#xff0c;可以加速SQL查询。但对于B树索引&#xff0c;它到底“长”得什么样子&#xff0c;它具体如何由一个个字节构成的&#xff0c;这些的基础知识鲜有人深究。本篇文章从…