详解#define

我们要知道,#define后面定义的标识符只进行替换而不进行计算,我们不能根据惯性自动给它计算了,这样可能会出错。


目录

1.关于#define

1.1#define定义标识符

1.2#define定义宏

1.3#define的替换规则

2.#和##

1.#

2.##

3.带副作用的宏参数

4.宏和函数的比较

5.命名的约定

6.#undef:可以移除宏定义


1.关于#define

1.1#define定义标识符

使用格式:#define name stuff

例如:#define MAX  1000   (这个是我们经常用到的)

          #define reg   register    为register创建一个简短的名字reg

          #define do_forever  for(  ; ; )   用更形象的符号来替换一种实现

          #define CASE break;case    写case语句的时候自动把break写上

我们可以举个代码例子来理解

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>

//CASE break 来举例

#define CASE break;case//它的意思就是把原来case的位置,替换为break;case
int main()
{
	int input = 0;
	int flag = 0;
	printf("请选择:>");
	scanf("%d ", &input);
	switch (input)
	{
	case 1:
		flag = 1;
	CASE 2:  
		flag = 2;
	CASE 3:
	    flag = 3;
	CASE 4:
		flag = 4;
	default:
		break;
	}
	printf("flag=%d\n", flag);
	return 0;
}

我们可以看到,对应CASE的位置被替换为 break;case  这样我们就不必每次都写break,因为我们有时会忘记写break,这样就很方便了,是不是很奇妙。

还有一点,在define定义标识符的时候,后面一般不要加“ ;”有时会出错误

还记得我们以前说过的悬空else吗,我们来举个例子:

#define MAX 100;

int main()
{
	int m = 0;
	scanf("%d", &m);
	if (m >= 0)
		m = MAX;
	else
		m = -1;
	printf("%d\n", m);
	return 0;
}

1.2#define定义宏

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

2.宏的申明方式:#define  name(parament_list) stuff

其中: name(parament_list)是指宏的参数

        parament_list是一个由逗号隔开的符号表,它可能出现在stuff中

        stuff是宏的内容

3.参数列表的左括号必须与name紧邻,如果二者之间有任何空白存在,参数列表就会被解释为stuff的一部分

我们看个例子:

#define SQUARE(x) x*x

int main()
{
	printf("%d\n", SQUARE(5));
	printf("%f\n", SQUARE(5.0));
	return 0;
}

但是这种定义方式存在隐患,我们之前说过#define定义的内容只进行替换而不计算,如果此时,我们把5改为5+1,它的值又是多少呢?

我们不妨先猜测一下,相信大多数人都回答36,但我们试着编译一下,发现结果和我们想象中不同

#define SQUARE(x) x*x

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

我们发现结果是11,并不是我们想想中的36,我们来解释一下

SQUARE(5+1)就是 5+1*5+1 =11

所以此时,我们又得到了几个注意点:

在写宏时,我们要勇于加括号,防止代码中进行替换时,代码结果可能出现错误

当我们希望计算结果是一个整体时,建议整体给stuff加括号

例如:#define SQUARE(x)   ((x)*(x))这样就不会出现错误了

同时,宏的参数也可以是多个

例子:

#define MAX(x,y) ((x)>(y)?(x):(y))

int main()
{
	int m = MAX(100, 443);
	printf("m=%d\n", m);
	return 0;
}

1.3#define的替换规则

虽然我们前面说define时可能已经说过了它的替换规则,但是在这里还是要给大家总结一下,方便大家总结:

在程序中扩展#define定义符号和宏时,需要涉及几个步骤:

1.在调用宏时,首先对参数进行检查,看看是否包含任何由define定义的符号,如果是,它们首先被替换

2.替换文本随后被插入到程序中原来的文本位置,对于宏,参数名被它们的值所替换

3.最后,再次对结果文件进行扫描,看看它是否包含任何由#define 定义的符号,如果是,就重复上述处理过程

注意:

1.宏参数和#define定义中可以出现其他#define定义的符号,但对于宏,不能出现递归

2.当预处理器搜索到#define定义的符号的时候,字符串常量的内容并不被搜索

2.#和##

1.#

 1.#它把参数插入到字符串中

2.用#把一个宏参数变为对应的字符串

这样说可能难以理解,我们直接看代码例子:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>

#define PRINT1(x) printf("the value of "#x" is %d\n",x)

#define PRINT2(format,x) printf("the value of "#x" is "format" \n",x)

int main()
{
	int a = 10;
	int b = 20;
	float f = 3.14f;
//#把宏参数插入到字符串中
	PRINT1(a);
	PRINT1(b);

//把宏参数变成对应的字符串
	
	PRINT2("%f", f);
	return 0;
}

2.##

1.##可以把位于它两边的符号合成一个符号

2.它允许宏定义从分离的文件片段创建标识符

但是我们要注意,这样的连接必须产生一个合法的标识符,否则其结果就是未定义的

看个代码例子:

#define CAT(x,y,z) x##y##z

int main()
{

	int iampig = 2023;
	printf("%d\n", CAT(i,am,pig));
	return 0;
}

3.带副作用的宏参数

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

#define MAX(x,y) ((x)>(y)?(x):(y))
int main()
{
	int a = 4;
	int b = 6;
	int m = MAX(a++, b++);//带有副作用的参数
	printf("a=%d  b=%d  m=%d \n", a, b,m);
	return 0;
}

我们本以为打印出来的会是5,7,6.为什么会这样呢?我们来分析一下

但如果我们把它封装成函数,它就不会有这个副作用,这是因为函数会先计算再传参,和宏不一样,只替换不计算

我们看个函数例子:

int Max(int x, int y)
{
	return (x > y ? x : y);
}
int main()
{
	int a = 4;
	int b = 6;
	int m = Max(a++, b++);
	printf("a=%d  b=%d  m=%d \n", a, b,m);
	return 0;
}

所以,接下来就引出了函数和宏的对比,让我们接着学习

4.宏和函数的比较

我们从以下七点进行比较:

1.代码长度

宏:每次使用时,宏代码都会被插入到程序中,除了非常小的宏之外,程序的长度会大幅度增长

函数:函数代码只出现于一个地方,每次使用这个函数时,都会调用那个地方的同一份代码

2.执行速度
宏:更快

函数:存在函数的调用和返回的额外开销,所以相对慢一些

3.操作符的优先级

宏:宏参数的求值是在所以周围表达式的上下文环境里,除非加上括号,否则邻近操作符的优先级可能会产生不可预料的后果,所以建议宏在书写的时候多加括号

函数:函数参数只在函数调用的时候求值一次,它的结果值传递给函数,表达式的求值结果更容易预判

4.带有副作用的参数

宏:参数可能被替换到宏体中的多个位置,所以带有副作用的参数求值可能会产生不可预料的结果

函数:函数参数只在传参的时候求值一次,结果更容易控制

5.参数类型

宏:宏的参数与类型无关,只要对参数的操作是合法的,它就可以使用任何参数类型

函数:函数的参数是与类型有关的,如果参数的类型不同,就需要不同的函数,即使它们执行的任务是相同的

6.调试

宏:宏是不方便调试的

函数:函数是可以逐语句调试的

7.递归

宏:不能递归

函数:可以递归

5.命名的约定

一般来讲,函数和宏的使用语法很相似,所以C语言没有规定它们的使用语法

我们约定俗成

宏命名就大写,函数名不要全大写

但有时宏也有小写特例,我们要注意

6.#undef:可以移除宏定义

这个函数是可以移除宏定义的,我们看个例子:


#define MAX 100

int main()
{
	printf("%d\n",MAX);//可以执行
#undef MAX
	//printf("%d\n",MAX);//不可执行
	return 0;
}

当我们#undef MAX后,在打印MXA,VS会提示我们MXA未定义,这就是它移除了宏定义。


好了,关于程序环境和预处理方面的知识,我们已经全部学完了,希望大家可以理解,关于C语言的理论方面的知识点到这里也是已经给大家全部说完了,对C语言说声拜拜。

我们下期再见!!!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

信息收集小练习

信息收集小练习 本文章无任何恶意攻击行为&#xff0c;演示内容都合规无攻击性 演示如何绕过cdn获取真实ip 使用多地ping该网站 发现有很多ip地址&#xff0c;证明有cdn 此处使用搜索引擎搜索&#xff0c;得到ip 演示nmap工具的常用参数 此处以testfire.net为例 使用多地p…

Android逆向实战 - MIUI调起三方应用系统拦截弹窗分析

近期&#xff0c;发现在部分Android手机调起其他应用时&#xff0c;会弹出一个系统弹窗拦截调起&#xff0c;需要用户二次确认。经过内部众测&#xff0c;发现绝大多数是小米手机&#xff0c;而且跟Android版本没有直接关系&#xff0c;猜测是MIUI某次升级引入的功能。这篇文章…

OpenCV入门教程

本文旨在让你快速入门opencv。 OpenCV OpenCV是计算机视觉中最受欢迎的库&#xff0c;最初由intel使用C和C 进行开发的&#xff0c;现在也可以在python中使用。该库是一个跨平台的开源库&#xff0c;是免费使用的。OpenCV库是一个高度优化的库&#xff0c;主要关注实时应用程…

Another app is currently holding the yum lock; waiting for it to exit...

今天使用yum进行下载的时候报错 解决办法&#xff1a; 执行 rm -f /var/run/yum.pid 然后重新运行yum指令即可&#xff0c;发现已经可以正常下载啦&#xff01;

VScode

一、VSCode设置中文 1、首先我们打开vscode&#xff0c;进入编辑页面后点击左边栏的图示图标进入“EXTENSIONS”面板 2、进入后&#xff0c;在上方搜索“Chinese”&#xff0c;搜索到中文&#xff08;简体&#xff09;后&#xff0c;点击“install”按钮。 3、等待自动下载安装…

STK Components 基础篇

1.开发包 STK Components 访问AGI官网&#xff0c;注册并登录后&#xff0c;从官网下载开发包&#xff1a;https://support.agi.com/downloads/&#xff0c;下载成功后可以申请许可证&#xff0c;AGI会向你注册的邮箱地址发送有效期半年的使用授权许可文件&#xff08;lic文件…

基于 STM32 的温度测量与控制系统设计

本文介绍了如何基于 STM32 微控制器设计一款温度测量与控制系统。首先&#xff0c;我们将简要介绍 STM32 微控制器的特点和能力。接下来&#xff0c;我们将详细讨论温度传感器的选择与接口。然后&#xff0c;我们将介绍如何使用 STM32 提供的开发工具和相关库来进行温度测量和控…

ubuntu20.04配置OpenCV的C++环境

ubuntu20.04配置OpenCV的C环境 这里以opencv-3.4.16为例 复现https://github.com/raulmur/ORB_SLAM2此项目&#xff0c;需安装opencv及其他依赖&#xff0c;可见README.md详情 1.下载opencv源代码 https://opencv.org/releases/ 2.下载OpenCV的扩展包opencv_contrib&#x…

排序算法-----基数排序

目录 前言 基数排序 算法思想 ​编辑 算法示例 代码实现 1.队列queue.h 头文件 2.队列queue.c 源文件 3.主函数&#xff08;radix_sort实现&#xff09; 算法分析 前言 今天我想把前面未更新完的排序算法补充一下&#xff0c;也就是基数排序的一种&#xff0c;这是跟…

小程序如何禁止指定用户访问?如何设置指定用户才能访问?

​有些商家为了价格保密或者实行严格的会员制等原因&#xff0c;希望小程序能够限制某些人的访问或者设置指定人员才能访问。这种功能在小程序中&#xff0c;怎么支持这些功能呢&#xff1f;下面具体介绍。 一、禁止指定用户访问 禁止指定用户访问&#xff0c;可以通过小程序…

【三极管锯齿波电路】2022-3-23

缘由以晶体管作恒流源的锯齿波电路工作原理? - 24小时必答区

【数据结构】树与二叉树(廿六):树删除指定结点及其子树(算法DS)

文章目录 5.3.1 树的存储结构5. 左儿子右兄弟链接结构 5.3.2 获取结点的算法1. 获取大儿子、大兄弟结点2. 搜索给定结点的父亲3. 搜索指定数据域的结点4. 删除结点及其左右子树a. 逻辑删除与物理删除b. 算法DSTc. 算法解析d. 代码实现递归释放树算法DS e. 算法测试 5. 代码整合…

基于C#实现三元组

我们知道矩阵是一个非常强大的数据结构&#xff0c;在动态规划以及各种图论算法上都有广泛的应用&#xff0c;当然矩阵有着不足的地方就是空间和时间复杂度都维持在 N2 上&#xff0c;比如 1w 个数字建立一个矩阵&#xff0c;在内存中会占用 1w*1w1 亿的类型空间&#xff0c;这…

【人工智能】Chatgpt的训练原理

前言 前不久&#xff0c;在学习C语言的我写了一段三子棋的代码&#xff0c;但是与我对抗的电脑是没有任何思考的&#xff0c;你看了这段代码就理解为什么了&#xff1a; void computerMove(char Board[ROW][COL], int row, int col) {while (1){unsigned int i rand() % ROW, …

BC76 [NOIP2008]ISBN号码

#include<stdio.h> int main() {char arr[13]; //存放13位的ISBNint i, j;scanf("%s",arr);int s 0;for(i0, j1; i<11; i){if(arr[i] ! -){s (arr[i]-0)*j; //将字符换成int累加&#xff1a;0162……29158j; //执行if的时候加&#xff0c;不执行不加…

Linxu 进程替换

进程替换的背景&#xff1a; 进程的替换我们需要调用execl这个接口,exxecl在3号手册&#xff0c;属于系统接口。 调用系统命令 execl 为了方便理解execl的作用&#xff0c;我们写一个程序&#xff1a; 单进程替换 我们发现运行结果是通过c库里的exec接口把系统命令 "l…

【深度学习】DAMO-YOLO,阿里,701类通用检测模型,目标检测

https://github.com/tinyvision/DAMO-YOLO/blob/master/README_cn.md DAMO-YOLO是由阿里巴巴达摩院智能计算实验室TinyML团队开发的一个兼顾速度与精度的目标检测框架,其效果超越了目前的一众YOLO系列方法&#xff0c;在实现SOTA的同时&#xff0c;保持了很高的推理速度。DAMO…

Error PostCSS plugin autoprefixer requires PostCSS 8

文章目录 一、情况一二、情况二三、总结 在启动 vue项目时&#xff0c;突然控制台报错&#xff1a; Error: PostCSS plugin autoprefixer requires PostCSS 8。然后依次出现下面几种情况&#xff0c;依次解决完&#xff0c;项目就可以正常启动了 一、情况一 error in ./src/…

【涂鸦T2-U】1、开发环境搭建

前言 本章介绍T2-U的开发环境搭建流程&#xff0c;以及一些遇到的问题。 一、资料 试用网址&#xff1a; 【新品体验】涂鸦 T2-U 开发板免费试用 涂鸦官网文档&#xff1a; 涂鸦 T2-U 开发板 T2-U 模组规格书 T2-U 开发板 淘宝(资料较全)&#xff1a; 涂鸦智能 TuyaOS开发…

软件测试职业规划导图

公司开发的产品专业性较强&#xff0c;软件测试人员需要有很强的专业知识&#xff0c;现在软件测试人员发展出现了一种测试管理者不愿意看到的景象&#xff1a; 1、开发技术较强的软件测试人员转向了软件开发(非测试工具开发)&#xff1b; 2、业务能力较强的测试人员转向了软件…