【C语言基础】宏定义的用法详解

📢:如果你也对机器人、人工智能感兴趣,看来我们志同道合✨
📢:不妨浏览一下我的博客主页【https://blog.csdn.net/weixin_51244852】
📢:文章若有幸对你有帮助,可点赞 👍 收藏 ⭐不迷路🙉
📢:内容若有错误,敬请留言 📝指正!原创文,转载请注明出处

文章目录

  • 引言:为什么使用宏定义?
  • 一、宏定义的定义
    • 1. 简单宏定义:
    • 2. 参数化宏定义:
    • 3. 字符串化宏定义:
    • 4. 连接宏定义:
    • 5. 条件宏定义:
    • 6.宏定义嵌套宏定义:
  • 二、宏定义需要注意的问题
  • 三、宏定义中为什么要加do和while(0)?


引言:为什么使用宏定义?

C语言中,一般都不会直接使用常量,而是先将其定义为一个宏,然后在程序中使用该宏名,进而调用了这个常量。
好处:修改方便。等我们需要修改这个常数时候,只需要在宏定义出修改一次即可。而不用到代码中到处去寻找,看哪里都用过这个常数。

一、宏定义的定义

在C语言中,宏定义是一种预处理指令,用于在编译之前将标识符替换为特定的值或代码片段。下面是几种常见的宏定义方式:

1. 简单宏定义:

#define 宏名 值

示例:

#define PI 3.14159
#define N (321)

定义N等于321。N在使用过程中会被321完全代替。注意不需要加“;”。其次,赋值的数值最好加上小括号。

2. 参数化宏定义:

#define 宏名(参数列表) 值或代码片段

示例:

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

3. 字符串化宏定义:

#define STRINGIFY(x) #x

示例:

printf("宏名: %s\n", STRINGIFY(MAX));
// 输出: 宏名: MAX

4. 连接宏定义:

#define CONCAT(a, b) a##b

示例:

int CONCAT(a, b) = 10;
// 相当于 int ab = 10;

5. 条件宏定义:

#ifdef 宏名
#ifndef 宏名
#endif

示例:

#define DEBUG
#ifdef DEBUGprintf("调试模式\n");
#endif

这些是C语言中常见的宏定义方式,使用宏定义可以在代码中提供一定的灵活性和可定制性。需要注意的是,宏定义是简单的文本替换,使用时需谨慎避免潜在的副作用和命名冲突。

6.宏定义嵌套宏定义:

#define M (N+5)
#define S(r) (PI*r*r)

宏定义的分类:对象宏和函数宏(函数宏顾名思义,就是行为类似函数)
例如:

#define a 3.14
#define N (a*a)

二、宏定义需要注意的问题

1.宏定义一般在函数的外面。
2.宏定义必须要先定义,再使用宏。如果先使用就会编译报错。
3.宏定义中宏名一般使用大写,便于区分变量名。不是语法规定的,是一般约定俗成的。

三、宏定义中为什么要加do和while(0)?

目的:在宏定义中添加do{...}while(0)结构的目的是为了将多个语句作为宏的一个整体,使其在代码中的使用更加灵活和安全。

宏展开后的代码会替代宏的调用部分,如果不使用do{...}while(0)结构,而是直接用花括号{...}包裹展开的代码,可能会导致在某些场景下产生语法错误或意想不到的行为。
下面是一些理由解释为什么要使用do{...}while(0)结构:

1.语法问题:do{...}while(0)结构保证了展开的代码作为一个完整的语句块存在。如果不添加这样的结构,并且将展开的代码用花括号包裹,可能会在某些情况下引起语法错误。使用do{...}while(0)结构能够确保展开的代码符合语法要求。

2.宏的调用位置:在一些特定的上下文中,宏的调用可能需要像普通的语句一样出现。例如,将宏用作函数调用的参数,或者将多个宏调用放在一个复合语句的条件部分。使用do{...}while(0)结构可以让宏的展开代码在这些情况下保持一致的行为。

3.语句的结束符号:由于宏展开后生成的代码可能包含多个语句,因此在每个语句的末尾都需要添加结束符号。使用do{...}while(0)结构可以确保在每个语句之后都添加了;分号,以避免语法错误。

总之,使用do{...}while(0)结构可以确保宏展开后的代码在各种上下文中具有一致的行为,避免语法错误,并且能够被作为单个语句来使用。这是一种常见的宏定义的惯用写法。

在这里插入图片描述

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

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

相关文章

angular中如何定义一个全局组件?

需求,我们需要新建一个navBreadcrumb的全局组件。这是一个面包屑导航,在不同的页面引入时传入一个路由数组即可。 第一步:我们新建这个组件: ng g c navBreadcrumb ng g m navBreadcrumb----------nav-breadcrumb.module-------…

vue中 .env .env.development .env.production 详细说明

1.配置文件有: .env 全局默认配置文件,不论什么环境都会加载合并 .env.development 开发环境下的配置文件 .env.production 生产环境下的配置文件 2.命名规则: 属性名必须以VUE_APP_开头,比如VUE_APP_XXX 3.关于文件的加载&#x…

【BASH】回顾与知识点梳理(三十一)

【BASH】回顾与知识点梳理 三十一 三十一. 进程的管理31.1 给进程发送讯号kill -signal PIDlinux系统后台常驻进程killall -signal 指令名称 31.2 关于进程的执行顺序Priority 与 Nice 值nice :新执行的指令即给予新的 nice 值renice :已存在进程的 nice…

uniapp的uview-plus组件库的导入

uniapp的vue3中使用uview-plus组件库。在插件市场中找到该组件并点击如下所示绿色按钮,弹出弹窗选择要导入的项目后,就会在uni_modules文件中生成如下文件内容 关于插件的下载区别,可参考:https://uniapp.dcloud.net.cn/compone…

信号

信号也是IPC中的一种,是和管道,消息队列,共享内存并列的概念。 本文参考: Linux中的信号_linux中信号_wolf鬼刀的博客-CSDN博客 Linux系统编程(信号处理 sigacation函数和sigqueue函数 )_花落已飘的博客-CSDN博客 Linu…

常用curl参数及样例讲解

1 缘起 后端/后台项目开发过程中,有两个阶段的接口测试和验证,自测阶段,通过Postman构建请求, 自建一些参数,测试功能以及边界条件,这些都是可以自行掌控的,当完成功能验证与前端对接时&#x…

19万字智慧城市总体规划与设计方案WORD

导读:原文《19万字智慧城市总体规划与设计方案WORD》(获取来源见文尾),本文精选其中精华及架构部分,逻辑清晰、内容完整,为快速形成售前方案提供参考。 感知基础设施 感知基础设施架构由感知范围、感知手…

正演的数值模拟(零基础,学习中)

摘要: 本贴从零开始学习正演的数值模拟方法. 1. 偏微分基础 引例: 物体从一维坐标的原点开始移动, 在 t t t 时刻, 它在坐标轴的位置由函数 s ( t ) s(t) s(t) 确定, 则速度为位置变化量与时间的比值: v ( t ) d s ( t ) d t lim ⁡ Δ t → 0 s ( t Δ t ) − s ( t )…

19-普通组件的注册使用

普通组件的注册使用-局部注册 一. 组件注册的两种方式:1.局部注册:只能在注册的组件内使用 (1) 创建 vue 文件(单文件组件) (2) 在使用的组件内导入,并注册 components:{ 组件名: 组件对象 } // 导入需要注册的组件 import 组件对象 from.vue文件路径 import HmHeader from ./…

使用 HTML、CSS 和 JavaScript 创建实时 Web 编辑器

使用 HTML、CSS 和 JavaScript 创建实时 Web 编辑器 在本文中,我们将创建一个实时网页编辑器。这是一个 Web 应用程序,允许我们在网页上编写 HTML、CSS 和 JavaScript 代码并实时查看结果。这是学习 Web 开发和测试代码片段的绝佳工具。我们将使用ifram…

如何找到一个数的所有质因数,以及如何快速判断一个数是不是质数

前情介绍 今天遇到一个需求&#xff1a;找到一个数所有的质因数。 初步解决 先定义一个判断质数的函数&#xff1a; def is_Prime(number):i 2count 0while i < number:if number % i 0 :count 1i 1if count > 0:return Falseelse:return True 接着定义一个寻找质…

【云原生】【k8s】Kubernetes+EFK构建日志分析安装部署

目录 EFK安装部署 一、环境准备&#xff08;所有主机&#xff09; 1、主机初始化配置 2、配置主机名并绑定hosts&#xff0c;不同主机名称不同 3、主机配置初始化 4、部署docker环境 二、部署kubernetes集群 1、组件介绍 2、配置阿里云yum源 3、安装kubelet kubeadm …

模型数据处理-数据放入 session和@ModelAttribute 实现 prepare 方法详细讲解

&#x1f600;前言 本文详细讲解了模型数据处理-数据放入 session和ModelAttribute 实现 prepare 方法详细讲解 &#x1f3e0;个人主页&#xff1a;尘觉主页 &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是尘觉&#xff0c;希望我的文章可以帮助到大家&#xff0c…

企业数字化转型大数据湖一体化平台项目建设方案PPT

导读&#xff1a;原文《企业数字化转型大数据湖一体化平台项目建设方案PPT》&#xff08;获取来源见文尾&#xff09;&#xff0c;本文精选其中精华及架构部分&#xff0c;逻辑清晰、内容完整&#xff0c;为快速形成售前方案提供参考。 喜欢文章&#xff0c;您可以点赞评论转发…

知识体系总结(九)设计原则、设计模式、分布式、高性能、高可用

文章目录 架构设计为什么要进行技术框架的设计 六大设计原则一、单一职责原则二、开闭原则三、依赖倒置原则四、接口分离原则五、迪米特法则&#xff08;又称最小知道原则&#xff09;六、里氏替换原则案例诠释 常见设计模式构造型单例模式工厂模式简单工厂工厂方法 生成器模式…

设计模式篇---抽象工厂(包含优化)

文章目录 概念结构实例优化 概念 抽象工厂&#xff1a;提供一个创建一系列相关或相互依赖对象的接口&#xff0c;而无须指定它们具体的类。 工厂方法是有一个类型的产品&#xff0c;也就是只有一个产品的抽象类或接口&#xff0c;而抽象工厂相对于工厂方法来说&#xff0c;是有…

Android Studio实现解析HTML获取图片URL,将URL存到list,进行列表展示

目录 效果build.gradle(app)添加的依赖(用不上的可以不加)AndroidManifest.xml错误代码activity_main.xmlitem_image.xmlMainActivityImage适配器ImageModel 接收图片URL效果 build.gradle(app)添加的依赖(用不上的可以不加) dependencies {implementation com.square…

Python可视化在量化交易中的应用(11)_Seaborn折线图

举个栗子&#xff0c;用seaborn绘制折线图。 Seaborn中折线图的绘制方法 在seaborn中&#xff0c;我们一般使用sns作为seaborn模块的别名&#xff0c;因此&#xff0c;在下文中&#xff0c;均以sns指代seaborn模块。 seaborn中绘制折线图使用的是sns.lineplot()函数&#xff…

中国剩余定理及扩展

目录 中国剩余定理解释 中国剩余定理扩展——求解模数不互质情况下的线性方程组&#xff1a; 代码实现&#xff1a; 互质&#xff1a; 非互质&#xff1a; 中国剩余定理解释 在《孙子算经》中有这样一个问题&#xff1a;“今有物不知其数&#xff0c;三三数之剩二&#x…

【C++】做一个飞机空战小游戏(十)——子弹击落炮弹、炮弹与飞机相撞

[导读]本系列博文内容链接如下&#xff1a; 【C】做一个飞机空战小游戏(一)——使用getch()函数获得键盘码值 【C】做一个飞机空战小游戏(二)——利用getch()函数实现键盘控制单个字符移动【C】做一个飞机空战小游戏(三)——getch()函数控制任意造型飞机图标移动 【C】做一个飞…