【零基础C语言】预处理解析

 

预定义符号

 c语言中设置一些预定的符号,我们可以直接使用

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

 / 续行符号

int main()
{printf("file = %s\nline = %d\ndate = %s\ntime = %s\n", \__FILE__, __LINE__, \__DATE__, __TIME__);return 0;
}

#define 用法

 //定义常量
#define max 100
int main()
{printf("%d\n", max);return 0;
}
 //给关键字创建一个别的名称
#define i int
i main()
{i a = 10;printf("%d\n", a);return 0;
}

我们平时使用代码时结尾都是以;,那么#define后面需不需要加上呢?

#define min 1;
#define max 1
int main()
{printf("%d\n", min); //errprintf("%d\n", max);return 0;
}

 答案是不能因为在预处理阶段,编译器会删除所有的#define,并且替换定义的变量
 拿上面的代码举例
 下面是预处理替换后的代码

int main()
{printf("%d\n", 1;);printf("%d\n", 1);return 0;
}

#define 定义宏 - 可以传入参数

 //比如: 
#define add(x) x * x
int main()
{printf("%d\n", add(2 + 1));return 0;
}

这段代码会输出多少?有木有小伙伴算的是9,毕竟3*3是9,那么这样就错了
下面我们一起来看看

首先我们前面了解到#define的内容会直接被替换
替换后

int main()
{printf("%d\n", 2 + 1 * 2 + 1);return 0;
}
// 根据优先级, 2+(1*2)+1 == 5
// 这种直接的替换往往也会带来一些小麻烦,要想解决也很容易,只要勤加()就行了
#define add(x) (x)*(x)
int main()
{printf("%d\n", add(2 + 1));return 0;
}
#endif//这样就不用担心优先级带来的麻烦了//这样就真的改好了吗,我们来看下面一段代码
#define add(x) (x)+(x)
int main()
{printf("%d\n", 10 * add(5)); //我们想要的结果是100return 0;
}// 输出的确实55,这还是犯了与上面同样的问题,我们的()加少了
// 最好的方案是在外面一层也加上#define add(x) ((x)+(x))
int main()
{printf("%d\n", 10 * add(5));return 0;
}

 带有副作用的宏参数

 举例:

#define MAX(a, b) ((a) > (b) ? (a) : (b))
int main()
{int a = 3;int b = 10;int z = MAX(a++, b++);printf("%d\n %d\n %d\n", a, b, z);return 0;
}//由上面的函数我们来进行替换
int main()
{int a = 3;int b = 10;int z = ((a++) > (b++) ? (a++) : (b++));// 先执行(a++)>(b++)  -  a=4, b=11;// 因为a<b, 所以执行表达式2(b++) - a=4,z=11,b=12printf("%d\n%d\n%d\n", a, z, b);return 0;
}//这就是宏参数的副作用,如果换成函数又如何呢?
int fution(int a, int b)
{return a > b ? a : b;
}int main()
{int a = 3;int b = 10;int z = fution(a++, b++);printf("%d\n%d\n%d\n", a, z, b);return 0;
}//我们可以看见z的结果是10,而a,b的结果分别加了1,函数在传参后函数中a与b不再改变。

宏替换的规则

  • 1.在调⽤宏时,⾸先对参数进⾏检查,看看是否包含任何由#define定义的符号。如果是,它们⾸先被替换。
  • 2. 替换⽂本随后被插⼊到程序中原来⽂本的位置。对于宏,参数名被他们的值所替换。
  • 3. 最后,再次对结果⽂件进⾏扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上述处理过程。

注意:

  • 1. 宏参数和#define定义中可以出现其他#define定义的符号。但是对于宏,不能出现递归。
  • 2. 当预处理器搜索#define定义的符号的时候,字符串常量的内容并不被搜索。
     

 宏函数的对比

// 宏函数常常应用于比较简单的运算// 如:比较大小// 宏写#define MAX(a, b)  ((a)>(b)?(a):(b))
int main()
{printf("%d\n", MAX(2, 3));return 0;
}// 函数写int MAX(int a, int b)
{return a > b ? a : b;
}
int main()
{printf("%d\n", MAX(2, 3));return 0;
}

为什么使用宏来运算而不使用函数
1. 相比较函数的调用,直接替换的计算工作时间更快
2. 宏与类型无关,你可以比较任意类型,然而函数却需要更改返回类型

宏函数的劣势
1.使用宏的时候,就相当于插入一段定义的代码,如果宏过长会导致代码太多,不好观察
2.宏无法调试
3.宏可能会带来优先级的问题,与类型也无关,不够严谨

 #和##

 #运算符

 //#运算符
// #运算符所执行的操作可以将宏中的一个参数转换为字符串字面量//如:我们有一个变量 int a = 20;
//我们想要使用宏然后打印出 the num of a is 20.#define PRINT(n) printf("the num of "#n " is %d",n);
int main()
{int a = 20;PRINT(a);return 0;
}当我们按照下⾯的⽅式调⽤的时候:
PRINT(a);//当我们把a替换到宏的体内时,就出现了#a,⽽#a就是转换为"a",这时⼀个字符串
代码就会被预处理为:
printf("the num of "a " is %d",a);

 ##运算符

#define FUNTION_MAX(type) \
type type##_max(type a, tpye b)\
{                              \return (a > b ? a : b); \
}// 这样使用后我们可以传入不同类型的参数了

 命名约定

 我们一般宏的使用命名时都全部大写,对于函数的应用却不全部大写

#undef

这条命令可以移除一个宏定义 

#define MAX 100
int main()
{printf("%d\n", MAX);
#undef MAXprintf("%d\n", MAX); //errreturn 0;
}

条件编译
有时我们需要用一段代码,但用后后面可能还要使用,我们希望保留,并且设定一个开关,这就是条件编译

#define __DEBUG__
int main()
{int i = 0;int arr[10] = { 0 };for (i = 0; i < 10; i++){arr[i] = i + 1;
#ifdef __DEBUG__printf("%d ", arr[i]);
#endif}return 0;
}
// 这样之后我们只有在前面定义 __DEBUG__ 我们才可以使用中间的代码

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

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

相关文章

基于SSM的高校普法系统(有报告)。Javaee项目。ssm项目。

演示视频&#xff1a; 基于SSM的高校普法系统&#xff08;有报告&#xff09;。Javaee项目。ssm项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;通过Spring Spri…

inkscape中文版本 G代码生成器(支持中英文及数字)使用

inkscape G代码生成器&#xff08;支持中英文及数字&#xff09;使用 1 inkscape安装1. 界面介绍2. 基本操作3. 图形编辑4. 图层管理5. 文件操作6. 高级功能7. 学习资源 2 laserengraver插件安装3 inkscape 使用candle 验证G代码效果 1 inkscape安装 跟着提示默认按键即可。 软…

HTML网站的概念

目录 前言&#xff1a; 1.什么是网页&#xff1a; 2.什么是网站&#xff1a; 示例&#xff1a; 3.服务器&#xff1a; 总结&#xff1a; 前言&#xff1a; HTML也称Hyper Text Markup Language&#xff0c;意思是超文本标记语言&#xff0c;同时HTML也是前端的基础&…

Git版本管理使用手册 - 5 - Git的.ignore文件语法

Git的.ignore文件 1.使用 .ignore文件可以忽略指定文件的版本控制。 2.语法&#xff1a; (1)#开头表示注释 (2)&#xff01;开头表示不忽略匹配文件 (3)* 表示除/外&#xff0c;任何字符串 (4)&#xff1f;表示除/外&#xff0c;任何一个字符 (5)/ 如果模式的结尾有分割符/&am…

Linux 环境安装Nginx—源码和Dokcer两种安装方式

一、源代码编译安装Nginx 1.下载最新nginx源码 以nginx-1.25.3.tar.gz为例&#xff1a; 可以使用命令(联网)&#xff1a;curl -O http://nginx.org/download/nginx-1.25.3.tar.gz或在官网下载.tar.gz 2.解压缩 tar -zxvf nginx-1.25.3.tar.gz cd nginx-1.25.3/ 3.安装依赖…

HarmonyOS实战开发-实现自定义弹窗

介绍 本篇Codelab基于ArkTS的声明式开发范式实现了三种不同的弹窗&#xff0c;第一种直接使用公共组件&#xff0c;后两种使用CustomDialogController实现自定义弹窗&#xff0c;效果如图所示 相关概念 AlertDialog&#xff1a;警告弹窗&#xff0c;可设置文本内容和响应回调…

【javaWeb 第八篇】后端-Mybatis(万字详细学习)

Mybatis框架 前言MybatisMybatis入门配置SQL提示JDBC数据库连接池lombok Mybatis基础操作日志输出Mybatis的动态SQL 前言 这篇是作者学习数据持久层框架Mybatis的学习笔记&#xff0c;希望对大家有所帮助&#xff0c;希望大家能够与作者交流讨论 Mybatis Mybatis是一款优秀的…

Android 开发 Spinner setSelection 不起作用

问题 Android 开发 Spinner setSelection 不起作用 详细问题 笔者进行Android项目开发&#xff0c;根据上一个页面用户选择数据&#xff0c;显示当前页面Spinner选项&#xff0c;调用 Spinner setSelection 不起作用。 相关java代码 spinner.setAdapter(adapter); …

uniapp对接萤石云 实现监控播放、云台控制、截图、录像、历史映像等功能

萤石云开发平台地址&#xff1a;文档概述 萤石开放平台API文档 (ys7.com) 萤石云监控播放 首先引入萤石云js js地址&#xff1a;GitHub - Ezviz-OpenBiz/EZUIKit-JavaScript-npm: 轻应用npm版本&#xff0c;降低接入难度&#xff0c;适配自定义UI&#xff0c;适配主流框架 vi…

C语言例4-35:鸡翁一,值钱五;鸡母一,值钱三;鸡雏三,值钱一。百钱买百鸡、问鸡翁、鸡母和鸡雏各几何?

方法一&#xff1a; 代码如下&#xff1a; //鸡翁一&#xff0c;值钱五&#xff1b;鸡母一&#xff0c;值钱三&#xff1b;鸡雏三&#xff0c;值钱一。百钱买百鸡、问鸡翁、鸡母和鸡雏各几何&#xff1f; //方法一&#xff1a; #include<stdio.h> int main(void) {int x…

简易挛生分拣系统设计

1 工效组合展示 2 方案规划设计 3 数字挛生建模 基础建模、动画设计、模型导出 4 软件体系架构 5 Web交互设计 5.1 页面架构 5.2 初始构造 5.3 模型运用 5.4 WS通信 5.5 运行展现 6 服务支撑编码 6.1 整体调度 6.2 WS服务 6.3 C/S通信 7 系统级调试完善

李雅普诺夫函数

李雅普诺夫函数是一种用于描述动力系统稳定性的数学工具。它在动力系统和控制理论中具有广泛的应用&#xff0c;尤其是在研究非线性系统的稳定性方面。 李雅普诺夫函数通常用于证明动力系统在一些条件下是稳定的。一个李雅普诺夫函数是一个实数值函数&#xff0c;通常表示为 V…

外文文献翻译以及阅读方法

翻译外文文献可以采取以下步骤&#xff1a; 阅读整篇文章&#xff0c;了解全文内容的大意和结构。 对文章进行逐段翻译&#xff0c;可以先用大意翻译整段&#xff0c;再细化到每个句子和词语。 在翻译过程中&#xff0c;要注意保持原文的逻辑结构和表达方式&#xff0c;尽量…

使用mybatis的@Interceptor实现拦截sql

一 mybatis的拦截器 1.1 拦截器介绍 拦截器是一种基于 AOP&#xff08;面向切面编程&#xff09;的技术&#xff0c;它可以在目标对象的方法执行前后插入自定义的逻辑。 1.2 语法介绍 1.注解Intercepts Intercepts({Signature(type StatementHandler.class, method “…

Python—数据类型转换

一&#xff1a;基本数据类型 1.数值类型 整型&#xff08;int&#xff09; 浮点型 &#xff08;float&#xff09; 虚数 num2 0b0011#二进制的数字前面加0b num8 0o0011#八进制的数字前面加0o num16 0x0011#十六进制的数字前面加0x print(num2,num8,num16)3 9 17 2.布尔类…

【Java - 框架 - Lombok】(2) SpringBoot整合Lombok完成日志的创建使用 - 快速上手;

"SpringBoot"整合"Lombok"完成日志的创建使用 - 快速上手&#xff1b; 环境 “Java"版本"1.8.0_202”&#xff1b;“Lombok"版本"1.18.20”&#xff1b;“Spring Boot"版本"2.5.9”&#xff1b;“Windows 11 专业版_22621…

华硕ROG幻X笔记本GZ301VV原厂OEM预装Win11系统安装包下载

ASUS华硕幻X电脑原装出厂Windows11系统&#xff0c;恢复出厂开箱状态系统 链接&#xff1a;https://pan.baidu.com/s/1RkPr5IscTUolYJVUrxTyhQ?pwdhob2 提取码&#xff1a;hob2 适用型号&#xff1a;GZ301VV、GZ301VU、GZ301VF 原装出厂系统自带所有驱动、出厂主题壁纸、系统…

如何让div中滚动条一直保持在最下方

设置div的scrollTop属性等于scrollHeight属性。 function onScrollChange() {const ele document.getElementById("test");ele.scrollTop ele.scrollHeight; }在React可以通过 ref 获取div元素 1.声明一个ref设置在div元素上 const testRef useRef(null)&#…

翔云身份证实名认证接口-PHP调用方法

网络平台集成实名认证接口&#xff0c;是顺应当下网络实名制规定&#xff0c;有效规避法律风险。互联网平台若没有实名认证功能&#xff0c;那么便无法保证网民用户身份的真实性&#xff0c;很有可能被虚假用户攻击&#xff0c;特别是在当网络平台产生垃圾信息乃至是违法信息时…

springmvc自定义http请求状态码

1.背景 在做微信支付后回调时,微信要求: 接收成功&#xff1a; HTTP应答状态码需返回200或204&#xff0c;无需返回应答报文。 接收失败&#xff1a; HTTP应答状态码需返回5XX或4XX&#xff0c;同时需返回应答报文 微信通知文档:支付通知 - H5支付 | 微信支付商户文档中心 …