C语言:define定义常量和定义宏(详解)

本篇博客给大家带来的是#define定义常量和#define定义宏的方法

🐟🐟文章专栏:C语言

🚀🚀若有问题评论区下讨论,我会及时回答

❤❤欢迎大家点赞、收藏、分享

你们的支持就是我创造的动力

今日思想:本来就一无所有,何必瞻前顾后呢!


 1、预定义符号

int main()
{printf("%s\n", __FILE__);//打印当前编译的源文件printf("%d\n", __LINE__);//代码的行号printf("%s\n", __DATE__);//文件编译的日期printf("%s\n", __TIME__);//文件被编译的时间printf("%d", __STDC__);//如果编译器遵循ANSIC则值为1,否则未定义return 0;
}

上面是C语⾔设置了⼀些预定义符号,可以直接使用,预定义符号也是在预处理期间处理的。

 2、define定义常量

基本语法:

#define 名字  常量

例如: 

#define M  10

 变态代码1:

#define forever for(;;);

这个代码一旦被使用,永远不会执行下面的代码

 变态代码2:

#define PRINT printf("the val of \
is %d\n",n);

注释:\是续行符。

上面的代码相当于:

 printf("the val of is %d\n",n);

 变态代码3:

#define CASE break;case

这个代码意思是:在写case语句的时候自动把break语句写上。

3、define定义宏

宏的基本语法:

#define name(parament-list) stuff

注意:参数列表的左括号必须与name紧邻,如果两者之间有任何空⽩存在,参数列表就会被解释为stuff的 ⼀部分。

代码实例: 

#define	DEV(n) n*nint main()
{int n = 10;int a = 4;printf("%d\n", DEV(n));printf("%d\n", DEV(a));return 0;
}

提示:#define DEV(n) n*n在预处理时会把使用DEV(n)的代码替换成n*n,上面代码替换之后会变成

这样: 

#define	DEV(n) n*nint main()
{int n = 10;int a = 4;printf("%d\n", n*n);printf("%d\n", a*a);return 0;
}

 特殊情况:

#define	DEV(n) n*nint main()
{int n = 10;int a = 4;printf("%d\n", DEV(n+1));printf("%d\n", DEV(a+1));return 0;
}

替换之后:

#define	DEV(n) n*nint main()
{int n = 10;int a = 4;printf("%d\n", n+1*n+1);printf("%d\n", a+1*a+1);return 0;
}

得出的结果和想象的不一样

所以要在宏的参数部分加上括号,即:

#define	DEV(n) ((n)*(n))int main()
{int n = 10;int a = 4;printf("%d\n", DEV(n+1));printf("%d\n", DEV(a+1));return 0;
}

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

 4、宏和函数的对比

函数实现加法:

//完成两个数的相加
int Add(int x, int y)
{return x + y;
}
int main()
{int n = 10;int a = 4;printf("%d\n", Add(n,a));//printf("%d\n", DEV(a));return 0

 宏实现加法:

#define	ADD(x,y) x+y
//完成两个数的相加int main()
{int n = 10;int a = 4;printf("%d\n", ADD(n,a));//printf("%d\n", DEV(a));return 0;
}

这两个方式都能实现加法,但是哪个更好呢???

使用宏的方式实现更好

原因如下:

1. 用于调⽤函数和从函数返回的代码可能比实际执行这个小型计算⼯作所需要的时间更多。所以宏比函数在程序的规模和速度方面更胜⼀筹。

2. 更为重要的是函数的参数必须声明为特定的类型。所以函数只能在类型合适的表达式上使用。反之这个宏怎可以适⽤于整形、⻓整型、浮点型等可以用于 > 来比较的类型。宏的参数是类型无关的。

和函数相比宏的劣势: 

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

2. 宏是没法调试的。

3. 宏由于类型无关,也就不够严谨。

4. 宏可能会带来运算符优先级的问题,导致程容易出现错。

 5、#和##号运算符

        5.1、#号运算符

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

代码示例:假如我们想打印the value of  a is 10


#define PRINT(n) printf("the value of "#n " is %d", n);
int main()
{int a=10;PRINT(a);return 0;
}

预处理替换之后:


#define PRINT(n) printf("the value of "#n " is %d", n);
int main()
{int a=10;printf("the value of "a " is %d", n);return 0;
}

        5.2、## 运算符

        ## 可以把位于它两边的符号合成⼀个符号,它允许宏定义从分离的文本片段创建标识符。 ## 被称为记号粘合 

 代码实例:

函数实现:

int int_max(int x, int y)
{return x > y ? x : y;
}

宏的实现方式:

#define GENERIC_MAX(type) \
type type##_max(type x, type y)\
{ \return (x>y?x:y); \
}

这两个代码一模一样

6、程序员的好习惯

宏的名字全部大小

函数名部分大写 

7、undef 

undef:用于移除一个宏定义 

代码实例:

int main()
{int n = 10;int a = 4;printf("%d\n", ADD(n,a));//printf("%d\n", DEV(a));
#undef ADD(x,y) x+yprintf("%d\n", ADD(n, a));//会报错return 0;
}

 8、条件编译

    调试性的代码,删除可惜,保留⼜碍事,所以我们可以选择性的编译。  

     代码实例:

#define M 10
int main()
{#ifdef MAX//如果定义了M则打印haha,这句代码相当于#if define(MAX)printf("haha\n");#endif//注意:#ifdef和#endif配套使用,#endif我的理解是结束if语句#ifndef M//如果没有定义M就打印hei hei,相当于#if !define(M)printf("hei hei\n");#endif // !M//如果没有定义M就打印hei heireturn 0;
}

注意:这样的语句在预编译的时候会选择编译,上面的代码相当于:

#define M 10
int main()
{printf("haha\n");return 0;
}

还有这样的代码:

int main()
{int x = 10;int y = 20;
#if(x>y)printf("%d", x);
#elif(x==y)//相当于else ifprintf("%d", y);
#elseprintf("%d", y);
#endifreturn 0;
}

选择编译后:

int main()
{int x = 10;int y = 20;printf("%d", y);return 0;
}

9、头文件的包含

        自己写的头文件用"",例如#include"name,h"

        库里面的头文件用<>,例如#include<stdio.h> 

自己写的头文件的查找文件:先在源文件所在⽬录下查找,如果该头文件未找到,编译器就像查找库函数头文件⼀样在标准位置查找头文件。 如果找不到就提示编译错误

库头文件的包含的查找方式:直接去标准路径下去查找,如果找不到就提示编译错误。

注意:其实库文件的包含也可以用"",但是比较费时间 

如果包含连续包含一模一样的头文件会耗费代码运行的时间,我们可以这样做来防止这样的事例发生:

 #pragma once

或者

#ifndef ___TEST_H__
#define<test.h>
#end

 完!!!

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

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

相关文章

Let up bring up a linux.part2 [十一]

之前的篇幅中我们已经将 Linux 内核 bringup 起来了&#xff0c;不知道大家有没有去尝试将根文件系统运行起来&#xff0c;今天我就带领大家完成这个事情&#xff0c;可以跟着下面的步骤一步步来完成&#xff1a; 在这里我们使用 busybox 构建 rootfs&#xff1a; 下载 busyb…

使用GO--Swagger生成文档

概述 在前后端分离的项目中&#xff0c;后端配置swagger可以很好的帮助前端人员了解后端接口参数和数据传输。go-swagger 是一个功能全面且高性能的Go语言实现工具包&#xff0c;用于处理Swagger 2.0&#xff08;即OpenAPI 2.0&#xff09;规范。它提供了丰富的工具集&#x…

pushgateway HA高可用方案

未经本人同意不得转载&#xff0c;若引用请附上原文链接。 项目使用flink来处理kafka中的无界流数据&#xff0c;采用的是flink on yarn的模式部署flink任务。最近做flink任务的监控过程中&#xff0c;踩了一些坑。下面是过程&#xff0c;只想看最终方案的直接拉到最后。 先说…

01-Chromedriver下载与配置(mac)

下载地址&#xff1a; 这里我用的最后一个&#xff0c;根据自己chrome浏览器选择相应的版本号即可 ChromeDriver官网下载地址&#xff1a;https://sites.google.com/chromium.org/driver/downloads ChromeDriver官网最新版下载地址&#xff1a;https://googlechromelabs.git…

使用docker-compose安装Milvus向量数据库及Attu可视化连接工具

首先确保系统已经安装上了docker 然后去https://github.com/docker/compose/releases/下载安装docker-compose 跟随自己下系统和服务器情况下载 上传到服务器 mv docker-compose-linux-aarch64 docker-compose chmod x docker-compose2.dockr-compose命令 docker-compose …

Conda + JuiceFS :增强 AI 开发环境共享能力

Conda 是当前 AI 应用开发领域中非常流行的环境和包管理系统&#xff0c;因其能够简单便捷地创建与系统资源相隔离的虚拟环境广受欢迎。 Conda 支持在不同的操作系统上重建相同的工作环境&#xff0c;但在环境共享复用方面仍存在一些挑战。比如&#xff0c;在不同机器上复用相…

【SpringBoot】31 Session + Redis 实战

Gitee https://gitee.com/Lin_DH/system 介绍 【SpringBoot】30 Cookie、Session、Token https://blog.csdn.net/weixin_44088274/article/details/144241595 背景 Spring Session 是 Spring 的一个子项目&#xff0c;它提供了一种管理用户会话信息的方法&#xff0c;无论…

关于网站的权重和百度蜘蛛爬虫的关系

网站的权重和百度蜘蛛爬虫的关系是密切关联的。 网站权重是一个衡量网站在搜索引擎中重要性的概念&#xff0c;它反映了网站在搜索引擎算法中的相对重要程度。而百度蜘蛛爬虫则是百度搜索引擎用来抓取网页内容的工具&#xff0c;通过分析网页的URL、内容、链接等因素来评估网站…

游戏引擎学习第35天

开场介绍 今天的任务是继续改进一个虚拟的瓦片地图系统&#xff0c;使其适合处理更大的世界。我们希望这个系统能管理大范围的游戏世界&#xff0c;其中包含按需存储的小区域。昨天&#xff0c;我们介绍了“内存区域”的概念&#xff0c;用于管理持久性存储。我们计划今天继续…

Leetcode经典题5--轮转数组

题目描述 给定一个整数数组 nums&#xff0c;将数组中的元素向右轮转 k 个位置&#xff0c;其中 k 是非负数。 输入输出示例 &#xff1a; 输入: nums [1,2,3,4,5,6,7], k 3 输出: [5,6,7,1,2,3,4] 解释: 向右轮转 1 步: [7,1,2,3,4,5,6] 向右轮转 2 步: [6,7,1,2,3,4,5] 向右…

【JS】简单CSS简单JS写的上传进度条

纯JS写的&#xff0c;简单的上传进度条&#xff0c;当上传的文件较大&#xff0c;加一个动态画面&#xff0c;就不会让人觉得出错了或网络卡了 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"v…

2023 年“泰迪杯”数据分析技能赛B 题企业财务数据分析与造假识别

2023 年“泰迪杯”数据分析技能赛B 题企业财务数据分析与造假识别 一、背景 财务数据是指企业经营活动和财务结果的数据记录&#xff0c;反映了企业的财务状况与经营成果。对行业、企业的财务数据进行分析&#xff0c;就是要评价其过去的经营业绩、衡量现在的财务状况、预测未…

perl Window安装教程

perl Window安装教程 下载地址 https://platform.activestate.com/tangxing806/ActivePerl-5.28/distributions 运行state-remote-installer.exe 按下图截图步骤 检查perl版本 参考文献&#xff1a; perl安装教程

知识图谱9:知识图谱的展示

1、知识图谱的展示有很多工具 Neo4j Browser - - - - 浏览器版本 Neo4j Desktop - - - - 桌面版本 graphX - - - - 可以集成到Neo4j Desktop Neo4j 提供的 Neo4j Bloom 是用户友好的可视化工具&#xff0c;适合非技术用户直观地浏览图数据。Cypher 是其核心查询语言&#x…

【数据分享】1901-2023年我国省市县三级逐年最低气温数据(Shp/Excel格式)

之前我们分享过1901-2023年1km分辨率逐月最低气温栅格数据和Excel和Shp格式的省市县三级逐月最低气温数据&#xff0c;原始的逐月最低气温栅格数据来源于彭守璋学者在国家青藏高原科学数据中心平台上分享的数据&#xff01;基于逐月栅格数据我们采用求年平均值的方法得到逐年最…

HBU深度学习实验15-循环神经网络(2)

LSTM的记忆能力实验 飞桨AI Studio星河社区-人工智能学习与实训社区 (baidu.com) 长短期记忆网络&#xff08;Long Short-Term Memory Network&#xff0c;LSTM&#xff09;是一种可以有效缓解长程依赖问题的循环神经网络&#xff0e;LSTM 的特点是引入了一个新的内部状态&am…

使用windows的包管理工具chocolatey

开发人员&#xff0c;在windows环境下&#xff0c;最头疼的是安装和配置各种环境变量&#xff0c;现在chocolatey 可以一键安装&#xff0c;不需要再去配置环境变量了。比如你安装一个java的环境&#xff0c;仅仅需要你敲几个命令&#xff0c;都能帮你搞定。 我自己已经使用这…

VTK知识学习(21)- 数据的读写

1、前言 对于应用程序而言&#xff0c;都需要处理特定的数据&#xff0c;VTK应用程序也不例外。 VTK应用程序所需的数据可以通过两种途径获取: 第一种是生成模型&#xff0c;然后处理这些模型数据(如由类 vtkCylinderSource 生成的多边形数据); 第二种是从外部存储介质里导…

QT 中 QString 转换为 Unicode 和 ASCII 的方法

目录 ​编辑 前言 一、QString转换成 Unicode编码 二、QString转换成ASCII编码 三、Unicode编码转换成QString汉字 四、ASCII编码转成QString 五、注意事项 六、总结 前言 在 Qt 开发中&#xff0c;经常会遇到需要将QString中的字符转换为特定编码格式的需求。本文将介…

基于51单片机64位病床呼叫系统设计( proteus仿真+程序+设计报告+原理图+讲解视频)

基于51单片机病床呼叫系统设计( proteus仿真程序设计报告原理图讲解视频&#xff09; 仿真图proteus7.8及以上 程序编译器&#xff1a;keil 4/keil 5 编程语言&#xff1a;C语言 设计编号&#xff1a;S0095 1. 主要功能&#xff1a; 基于51单片机的病床呼叫系统proteus仿…