关于#define的一些小知识

这篇具有很好参考价值的文章主要介绍了关于#define的一些小知识。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

一,#define的声明格式:

二,#define宏的作用是为了完成替换

#define的替换规则:   

三,#define使用时常犯的错误

四,宏与函数的比较

4.1,什么时候使用宏?

4.1,使用宏的好处与坏处

4.3宏的奇怪用法


一,#define的声明格式:

#define name( parament-list ) stuff

关于#define格式需要注意的几个点:

1.在stuff后面不能有冒号

2.name要和左圆括号紧贴在一起

 🌰:使用#define定义一个 求两者间较大值的宏:

#define MAX(a,b) a>b?a:b

二,#define宏的作用是为了完成替换

#define的替换规则:   

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

比如以下代码:

#define MAX(a,b) a>b?a:b
#include<stdio.h>
int main() {
	int a = 10;
	int b = 5;
	printf("%d\n", MAX(a, b));
}

在程序预处理的过程中就会变成这样:

#define MAX(a,b) a>b?a:b
#include<stdio.h>
int main() {
	int a = 10;
	int b = 5;
	printf("%d\n",a>b?a:b);//MAX(a,b)直接被替换掉
}

这也就解释了为什么在宏定义语句的末尾为什么不能加 ;(分号),假如我在宏定义后面加了分号:

#define MAX(a,b) a>b?a:b;

那在替换过程中,MAX(a,b)就会被替换成这样:

 a>b?a:b;
#define MAX(a,b) a>b?a:b
#include<stdio.h>
int main() {
	int a = 10;
	int b = 5;
	printf("%d\n",a>b?a:b;);//明显就是一个错误的代码
}

所以我们便不能在宏定义后面随意加上;(冒号)。

三,#define使用时常犯的错误

3.1不加括号:

#define MUL(a,b) a*b //参数不加括号

现在我让a=2+1,b=2+1代入下列代码中:

#include<stdio.h>
#define MUL(a,b) a*b
int main() {
	int c = MUL(2+1, 2+1);
	printf("%d\n", c);
	return 0;
}

结果:5   

但是我们都知道3*3等于9,所以这个代码为什么会错呢?

原因其实很简单,因为宏会直接替换,也就是宏其实是不会计算的。 所以这段宏就会被替换成这样:

#define MUL(2+1,2+1) 2+1*2+1//c=2+1*2+1=5
int main() {
	int c = MUL(2+1, 2+1);
	printf("%d\n", c);//c=5
	return 0;
}

所以结果就变成5了。

在这里做一个小小的改动:

#include<stdio.h>
#define MUL(a,b) (a)*(b)//加两个括号
int main() {
	int c = MUL(2+1, 2+1);
	printf("%d\n", c);
	return 0;
}

于是宏替换就会变成这个样子:

#define MUL(2+1,2+1) (2+1)*(2+1)//c=(2+1)*(2+1)=9
int main() {
	int c = MUL(2+1, 2+1);
	printf("%d\n", c);//c=5
	return 0;
}

输出:9

但是仅仅做到这样有时候是不保险的:

比如:

🌰:

#define MUL(a,b) (a)+(b)

#define MUL(a,b) (a)+(b)
int main() {
	int c = 10*MUL(3, 3);//计算的值应该是60
	printf("%d\n", c);
	return 0;
}

但是:

输出:33

 因为在这里宏替换以后,宏会变成这样:

#define MUL(a,b) (3)+(3)
int main() {
	int c = 10*(3)+(3);//相当于10*3+3==33
	printf("%d\n", c);
	return 0;
}

在这里就有一个解决方案:

#define MUL(a,b) ((a)+(b))//再加一个大括号
int main() {
	int c = 10*MUL(3, 3);//计算的值应该是60
	printf("%d\n", c);
	return 0;
}

这样就可以得到我们想要的60了。

四,宏与函数的比较

4.1,什么时候使用宏?

在这里我们有一个基本的常识:

   1.实现简单的功能时使用宏。

比如:求两个数的较大值

#define MAX(a,b) ((a)>(b)?(a):(b))

2.实现复杂功能时用函数。

4.1,使用宏的好处与坏处

好处:

1.宏在小型程序中执行的时候更加有效率

2.宏是没有类型的,所以调用的时候更加方便

坏处:

1.无法调试

2. 每次使用宏的时候,一份宏定义的代码将插入到程序中。除非宏比较短,否则可能大幅度增加程序 的长度。

 

4.3宏的奇怪用法

比如使用 malloc这个函数:

正常使用:

#include<stdio.h>
#include<stdlib.h>
int main() {
	int* arr = (int*)malloc(20);
	if (*arr == NULL) {
		perror("malloc:");
		return;
}
	//使用

	//关闭
	free(arr);
	arr = NULL;
    return 0;
}

使用宏:

先定义宏:

#define MALLOC(type,nums) (type)malloc(nums*sizeof(type))

然后就可以这样使用:

#include<stdio.h>
#include<stdlib.h>
#define MALLOC(type,nums) (type)malloc(nums*sizeof(type))
int main() {
	int* arr = MALLOC(int*,20);
	if (*arr == NULL) {
		perror("malloc:");
		return;
	}
	//使用

	//关闭
	free(arr);
	arr = NULL;
	return 0;
}

今天分享完毕。。。。文章来源地址https://www.toymoban.com/news/detail-407431.html

到了这里,关于关于#define的一些小知识的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 关于umask(权限掩码)的一些知识

    前言:首先,我们先介绍一下关于umask的一些基础知识,以方便更深入的了解umask 定义: umask(user-file-creation mode mask)用户文件创建权限掩码,是linux系统或类linux系统的一个命令,是有3个八进制位数组成,取值范围是 0000 - 0777 ,或者可简写为 000 - 077 ,第一个 0 是用来标识

    2024年02月07日
    浏览(44)
  • 关于Windows命令行(cmd)的一些知识

    CMD命令是一种命令提示符,CMD是command的缩写,即命令提示符(CMD),位于C:WindowsSystem32的目录下。 这个玩意我觉得很方便也很酷。下面我来介绍一下我平时用到的cmd操作。 如何使用cmd命令快速打开电脑软件,告别桌面快捷方式!! 打开“此电脑”,在空白处右键,点击“

    2024年02月08日
    浏览(32)
  • C语言中关于#include的一些小知识

    写代码的过程中,因为手误,重复包含了头文件 可以看到没有报错 如果是你自己编写的头文件,那么如果没加唯一包含标识的话,那么编译器会编译报错的。如果是系统自带的头文件,由于其每个头文件都加了特殊标识,所以即使你包含两遍,也不会有问题。 在C语言中,如

    2024年02月21日
    浏览(36)
  • 关于set变更通知涉及的一些知识点

    在这个示例中,我们声明了一个私有字段  _name  作为存储名称的后端字段,并将其封装在公共属性  Name  中。在 setter 方法中,我们首先检查新值是否与旧值相同。如果不同,我们才更新存储字段,并调用  OnNameChanged()  方法来引发  NameChanged  事件。 注意, OnNameChanged  方

    2024年02月08日
    浏览(48)
  • 关于网络通信安全协议的一些知识(ssl,tls,CA,https)

    首先了解一下http协议的变迁。 http1.0默认短连接,1.1默认长连接并且可以管道传输,但是存在队头阻塞问题; https就是在tcp和http之间加了SSL/TLS层。 http2也是安全的,改进是hpack二进制和编码压缩减小体积,stream没有队头阻塞了(TCP层还有),以及服务器主动推送功能; http

    2024年02月15日
    浏览(54)
  • qt qtcreator qt+vs 编译器 关于QT、QT creator和编译器,新手入门必知的一些知识关于QT、QT creator和编译器,新手入门必知的一些知识_qt和qtcreator的区别_炫彩灵感的博客-CSDN博客

    对于一个新手而言,基本体会如下: Qt Creator Qt Creator优势 可以实现Ui和代码无缝切换。(VS不行) 对于汉字的支持更好 提示功能做的更好。 比如:#include等,敲出#inc即有提示。 qmake非常好用 项目管理更方便,可以添加pri之类的来管理子模块 Qt Creator劣势(IDE本身巨大劣势)

    2024年02月11日
    浏览(60)
  • 关于goland的一些坑

    主要是做个记录,供自己看 注意goland中的GOPATH配置: Global GOPATH直接影响这个项目的终端go env中的GOPATH Use GOPATH that’s define in system environment,勾选意思是:将Global GOPATH作为Project GOPATH index entire GOPATH,勾选:将project GOPATH加入到go env中的GOPATH环境变量中 一般建议是,在创建项

    2024年02月03日
    浏览(47)
  • 关于一些代码习惯

    修改完代码,记得自己测试一下 方法入参尽量都检验 修改老接口的时候,要先思考接口的兼容性 复杂的代码逻辑,添加清楚的注释 尽量不在循环里远程调用、数据库操作,要优先考虑批量进行 手动写完业务代码的SQL,先拿去数据库运行一下,同时也explain看下执行计划 调用

    2024年02月21日
    浏览(41)
  • 关于账号安全的一些思考

    目录 声明 0x01-提升账号安全的目的 0x02-问题分析 1、攻击思路 1.1、页面关键点拆解 1.2、关于提升账号成本 2、攻击行为 3、黑产资源 维度1:资源 维度2:作弊工具 0x03-矛与盾 资源维度 1、IP资源 1.1、IP资源介绍 1.2、攻击方式 (1)IP池实现逻辑 (2)IP池页面展示 1.3、防御思路

    2023年04月10日
    浏览(40)
  • 关于Nginx的一些脚本

    文章目录 目录 文章目录 前言 一、Nginx 访问日志分析脚本 二、Nginx 访问访问日志按天切割 总结 脚本经常用于自动化特定任务。通过编写脚本,可以轻松地执行重复性、复杂或耗时的操作,如文件处理、数据转换、系统管理等,脚本可用于批处理任务,即按照一系列预定义的

    2024年02月11日
    浏览(32)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包