#define定义

server/2024/9/23 9:23:51/

1.define定义常量

比如

#define max  100

我们就可以用max来代替100使用了。

#define saying "hello world"

我们就可以使用saying代替"hello,world"使用了

但是要注意的是,我们最好不要在最后面加上分号,有时候容易出错

比如

#include <stdio.h>
#define a 0;
int main(void)
{int b;if (0)b = a;elseb = 1;return 0;
}

这个时候a替换过去就是

b=a;;

编译器会吧b=a;识别成一条语句

;识别出另一条语句(空语句)

这个时候if没加括号,就会导致if else使用出错。

2.define 定义宏

我们直接上例子理解

这个地方的宏类似于函数,但是又不同于函数(后面会解释) 

cal(a)就是 4*4=16没问题

但是为啥cal(b)就等于23呢?

#define无论是定义常量还是宏,都是预处理的时候直接替换的

也就是cal(b)=cal(3+5)=3+5*3+5=3+15+5=23;

因此我们在使用宏的时候,不要吝啬括号。

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

 因此像这样改就可以了

但是要注意定义宏时要将宏的名字紧挨左括号,不然如果有空隙就成了定义常量了

注意:最好不要使用带有副作用的参数
当宏参数在宏的定义中出现超过一次的时候,如果参数带有副作用,那么你在使用这个宏的时候就可能出现危险,导致不可预测的后果。

副作用就是表达式求值的时候出现的永久性效果。

#include <stdio.h>
#define cal(a,b) ((a++)>(b++)?(a++):(b++)) 
int main(void)
{int a = 4;int b = 3;printf("%d\n", cal(a,b));printf("%d\n", a);return 0;
}

比如这串代码,虽然cal(a,b)的的值是5,但是此时再去打印a就是6了,如果我们不打印的话,就很容易将a的值当作5去使用,而且根据a和b的值大小不同,a++,b++的次数也不固定,很容易导致不可预测的后果,因此不要使用带有副作用的宏。

总结:

宏替换的规则
在程序中扩展#define定义符号和宏时,需要涉及几个步骤。
1.在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号。

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

比如

#include <stdio.h>
#define cal(a,b) ((a++)>(b++)?(a++):(b++)) 
int main(void)
{int a = 4;int b = 3;printf("cal(a,b)");return 0;
}

这个时候打印出来的结果就是字符串cal(a,b)

3.宏和函数的优劣

接下来我们来看函数和宏的优缺点

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

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

#include <stdio.h>
#include <stdlib.h>
#define MALLOC(n,type) (type*)malloc(n*sizeof(type)) 
int main(void)
{int* a = MALLOC(20, int);return 0;
}

宏这个地方就可以传类型了,这是函数做不到的

最后以一张表格来对比宏和函数优劣

3.#运算符和##运算符

(1)#运算符

、比如说我们希望做一个宏或者函数

假设int a=3  float b=4

比如输入 "%d",a

打印出来the value of a is 3

输入 "%f" ,b

打印出来是the value of b is 4

显然这用函数是无法实现的

因为the value of is 3

a

是不可变的,我再输入 "%f" ,b

打印出来的是the value of a is 4

那我们来一串宏试试可不可行

#include <stdio.h>
#include <stdlib.h>
#define WORK(format,n)  printf("the value of n is "format"\n",n)
int main(void)
{int a = 4;WORK("%d", a);return 0;
}

 但是我们这个时候发现这个宏也无法解决这个问题,打印出来的是the value of n is 4

而不是the value of a is 4

 这个时候我们的#运算符就可以起到作用了,但是再此之前我们要回顾一点

就是两个连续的字符串会被自动连接一个字符串

因此我们就可以这样写代码

这样就可以达到我们的效果了

#运算符
运算符将宏的一个参数转换为字符串字面量。

它仅允许出现在带参数的宏的替换列表中。
#运算符所执行的操作可以理解为”字符串化“。

我们输入 "%d",a

会变成printf("the value of " "a" " is "format"\n",n);

(2)##运算符

## 运算符
## 可以把位于它两边的符号合成一个符号,它允许宏定义从分离的文本片段创建标识符。#被称为记号粘合
这样的连接必须产生一个合法的标识符。否则其结果就是未定义的。
比如说我们比较两个数的大小,int类型的值比较要写一个函数,浮点数类型的还要写一个函数,太麻烦了。

使用宏可以很好的解决问题

#include <stdio.h>
#include <stdlib.h>
#define GENERIC_MAX(type)\
type type##_max(type x,type y)\
{                             \
return (x > y ? x : y);       \
}
GENERIC_MAX(float)//替换到宏体后float##_max生成新的符号 int_max做函数名
GENERIC_MAX(int)//替换到宏体后int##_max生成新的符号 float_max做函数名
int main(void)
{//调用函数int m = int_max(2, 3);printf("%d\n", m);float n = float_max(2.5f, 3.5f);printf("%f\n", n);return 0;
}

一个宏声明未结束,句尾要加上\符

(3) #undef
这条指令用于移除一个宏定义。

(4)命名约定
-般来讲函数的宏的使用语法很相似。所以语言本身没法帮我们区分二者。
那我们平时的一个习惯是:
把宏名全部大写
函数名不要全部大写


http://www.ppmy.cn/server/120735.html

相关文章

在Java中,有没有其他方式可以替代List<Map<String,Object>>来存储和处理数据?

在Java中&#xff0c;有多种方式可以替代List<Map<String, Object>>来存储和处理数据。选择哪种方式取决于你的具体需求&#xff0c;比如数据结构的复杂性、类型安全、性能要求等。以下是一些常见的替代方案&#xff1a; 自定义类&#xff08;POJOs&#xff09;&am…

python基础(1)pyenv安装和对Django使用

pyenv安装 pyenv主要针对类 Unix 系统&#xff08;如 Linux、macOS&#xff09;用户&#xff0c;pyenv-win 是专为 Windows 开发的 pyenv 版本&#xff0c;允许您在不使用 WSL 的情况下管理多个 Python 版本和虚拟环境。 建议Git Bash&#xff1a; Powershell或Git Bash&…

【计算机网络】TCP的可靠传输机制、标记位以及编程结构

文章目录 一、TCP的可靠传输的工作原理1、确认应答机制和捎带应答机制2、超时重传3、快速重传4、滑动窗口5、流量控制 未 PSH6、拥塞控制7、延迟应答8、TCP 以段为单位发送数据 二、TCP 首部的六个标记位1、URG2、ACK3、PSH4、RST5、SYN6、FIN 三、TCP网络并发编程 一、TCP的可…

web网站的任意文件上传下载漏洞解析

免责申明 本文仅是用于学习检测自己搭建的任意文件上传下载漏洞相关原理,请勿用在非法途径上,若将其用于非法目的,所造成的一切后果由您自行承担,产生的一切风险和后果与笔者无关;本文开始前请认真详细学习《‌中华人民共和国网络安全法》‌及其所在国家地区相关法规内容【…

Oracle DB运维常用的视图及数据字典

List item 本文介绍一些Oracle DB日常运维最常用到&#xff08;使用频率很高&#xff09;的视图及数据字典 用户有关的常用视图&#xff1a; 1、 查看当前用户的缺省表空间* SQL>select username,default_tablespace from user_users; 2、 查看当前用户的角色 SQL>sele…

除猫毛用粘毛器还是宠物空气净化器?希喂/米家/352/范罗士/有哈空气净化器对比

微博之夜&#xff0c;明星互送礼物环节&#xff0c;要求所有嘉宾准备一份礼物&#xff0c;再由其他明星随机抽取互换礼物。田曦薇送粘毛器可是引起了广泛的争议和批评。不说价格&#xff0c;粘毛器对咱养猫人来讲还真是刚需啊。我朋友家三只猫&#xff0c;出门不用说啥&#xf…

Unity 设计模式 之 创建型模式 -【单例模式】【原型模式】 【建造者模式】

Unity 设计模式 之 创建型模式 -【单例模式】【原型模式】 【建造者模式】 目录 Unity 设计模式 之 创建型模式 -【单例模式】【原型模式】 【建造者模式】 一、简单介绍 二、单例模式 (Singleton Pattern) 1、什么时候使用单例模式 2、单例模式的好处 3、使用单例模式的…

聚焦于 Web 性能指标 TTI

在优化网站性能的过程中&#xff0c;我们经常遇到一个“为指标而优化”的困境。指标并不能真正反映用户体验&#xff0c;而应该最真实地反映用户行为。 在本节中&#xff0c;我们将研究 TTI&#xff08;Time to Interactive&#xff09;。在深入探讨这个话题之前&#xff0c;我…