C语言中的宏

news2024/11/24 7:27:38

宏定义又称为宏替换,简称“宏”,在C语言预处理阶段被处理,编译器会根据宏定义进行文本替换。这样做的好处有许多,它可以为程序员在编程时提供方便,并能在一定程度上提高程序的运行效率。

本文将通过一部分场景,来学习一些和宏相关的知识。

#define

  1. 采用宏定义一些常用常量,避免在代码中出现magic number:

#define PI 3.1415926
#define ERROR -1
#define NULL (void*)0
#define EOF (-1)
......

2. 用宏定义避免头文件重复引用,很常见,等价于#pragma once

#ifndef _XXXX_H_
#define _XXXX_H_
......
#endif

这样做相较于#pragma的优点是,所有的编译器都能达到想要的效果(有的编译器可能不支持#pragma once),缺点是,宏定义重复可能带来问题。

3. 一些常用的简单函数,使用宏函数实现,防止出错,也省得打字。宏函数名和括号之间不能有空格!

#define ADD(a,b) (a+b)
#define RND8( x )       ((((x) + 7) / 8 ) * 8 ) 返回一个比x大的8的倍数
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) 得到某个结构体成员相较于结构体头部的偏移
......

4. 通过宏,可以用代码段进行替换,为了代码美观,可以使用\换行,宏函数可以具有返回值,最后一行的值为返回值。同时,宏之间可以嵌套调用,下例中就嵌套调用了上例中的offsetof:

内核中相当著名的container_of宏定义实现:
它具有返回值,最后一行返回了该member所在的结构体的内存中起始位置
#define container_of(ptr, type, member) ({      \
  const typeof(((type *)0)->member) * __mptr = (ptr);  \
  (type *)((char *)__mptr - offsetof(type, member)); })

用法是:

(type*) p = container_of(成员指针, 成员结构体类型, 成员名)

5. 很魔幻的用法,可以将输入转换为单双引号字符串或者将输入串联起来。

##把输入串联起来

#define CONN(a, b) a##b

e670f30b8deff0e522650abb0a5558f2.png

#@把输入转换为单引号字符串

#把输入转换为双引号字符串

#define CONN(a, b) #@a###b

efc02e26d4862ca1ad284cc76c0ead10.png

这个魔幻的操作有什么用途呢?

比如我们想要对磁盘命名 disk1 disk2 disk3,它们是字符串,就可以用宏定义的方式,迅速转换,快速填充。

6. 一些编译器的特殊用法,比如可变长参数表,编译器优化等:

ANSI标准说明了五个预定义的宏名。它们是:
__LINE__
__FILE__
__DATE__
__TIME__
__STDC__
__VA_ARGS__与##__VA_ARGS__(##__VA_ARGS__可以在可变参数个数为0时,去掉最后的逗号)

注意!!

在宏定义使用时,也有一些容易出问题的地方需要注意。

  1.  善用小括号:

不使用小括号,可能带来错误:

#define add(a, b) a+b
当计算:
add(2, 2) * add(2, 2)
经过编译器预处理:
2 + 2 * 2 + 2
导致错误。
因此正确写法为:
#define add(a, b) (a + b)

2. do{}while(0) 有妙用:

这个循环本质上只会执行一次,但是采用这样的写法的作用是首先使得宏定义替换后的代码在一个独立代码段中,局部变量可以重复定义不受影响,其次即使传入参数为空,编译器也不会警告。

同时,对于以下情况,能避免错误:

#define cond(arg) if(arg) dosomething;
假设该宏被用在
if(condition)
cond(A)
else 
B
展开后:
if(condition)
if(A) dosomething;
else
B
这个if-else的配对关系就被“误解”了导致出错。

那么为什么要用do...while(0)呢?似乎用一个大括号{}也能解决问题。目的是防止出现错误的分号:

#define cond(arg) {if(arg) dosomething;}
假设该宏被用在
if(condition)
cond(A);
else 
B
展开后:
if(condition)
{if(A) dosomething;};
else
B
会发现,多了一个分号,导致编译错误。
所以,使用do-while结构,形成一个语法单元,能避免此类错误
同时,无效的循环基本都会被编译器优化,不会造成性能下降。


因此,正确写法:
#define cond(arg) do{if(arg) dosomething;}while(0)

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

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

相关文章

原码、反码和补码之间的转换

(꒪ꇴ꒪(꒪ꇴ꒪ ),hello我是祐言博客主页:C语言基础,Linux基础,软件配置领域博主🌍快上🚘,一起学习!送给读者的一句鸡汤🤔:集中起来的意志可以击穿顽石!作者水平很有限,如果发现错误…

DataEase中点数据集,报Data source connection exception: Access denied for user错误

【现象】&#xff1a; 2023-07-12 10:53:19,436 DEBUG .DeEngineMapper.selectByExampleWithBLOBs: 137 - < Total: 1 java.sql.SQLException: Access denied for user ****** (using password: YES)at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:965…

MySQL基础篇第8章(聚合函数)

文章目录 1、聚合函数介绍1.1 AVG和SUM函数1.2 MIN和MAX函数1.3 COUNT函数 2、GROUP BY2.1 基本使用2.2 使用多个分组2.3 GROUP BY中使用WITH ROLLUP 3、HAVING3.1 基本使用3.2 WHERE和HAVING的对比 4、SELECT的执行过程4.1 查询的结构4.2 SELECT执行顺序4.3 SQL的执行原理 1、…

【MQ】Windows上RabbitMQ的安装与启动

文章目录 下载Erlang安装RabbitMQ 下载Erlang RabbitMQ基于Erlang语言&#xff0c;因此使用RabbitMQ之前需要先安装Erlang&#xff0c;如下 Erlang语言下载 这里我是用的是25.2.2这个版本&#xff0c;我的机器是64bit的&#xff0c;所以下win64的即可。 下载完毕安装包之后点…

Wholebody 3D keypoint估计:从H3WB开始

目录 前言一、&#xff28;&#xff13;&#xff37;&#xff22;1.下载2.标注格式3.任务分析验证评估 总结 前言 这份工作是首次尝试去检测&#xff13;D全人体姿态的工作&#xff0e;我们使用的数据集是基于Human3.6M的&#xff13;&#xff24;全人体关键点数据集&#xff…

【宝塔】宝塔部署ThinkPHP项目

最近搞了个培训教育的小程序&#xff0c;后端服务用的是ThinkPHP。使用的过程中&#xff0c;发现对于这种小项目用php还是很不错的选择&#xff0c;开发便捷&#xff0c;轻量级。宝塔神器也是很不错的&#xff0c;值得推荐使用。 下面介绍一下项目中用宝塔部署ThinkPHP项目&…

USB枚举过程详解

1 USB枚举流程 1.1 USB枚举流程 USB SETUP command的状态阶段的状态包是个ZLP。 Anchor chips -> Netchip -> PLX -> Avago -> Broadcom The USB3380 is EOL and the kits that were by Taiwan Bplus. PLX USB3380设备控制器使用2个32bit寄存器存放setup的8个字节&…

数据库-表的增删改查

这里写目录标题 新增&#xff08;Create&#xff09;查询条件查询运算符逻辑运算符分页查询 修改&#xff08;Update&#xff09;删除&#xff08;Delete&#xff09; 注释&#xff1a;在SQL中可以使用“–空格描述”来表示注释说明 新增&#xff08;Create&#xff09; 语法…

spark3新特性之动态分区裁剪

Spark3.0为我们带来了许多令人期待的特性。Spark中的静态分区裁剪在介绍动态分区裁剪之前&#xff0c;有必要对Spark中的静态分区裁剪进行介绍。因此&#xff0c;在这种情况下&#xff0c;我们不能再应用静态分区裁剪&#xff0c;因为filter条件在join表的一侧&#xff0c;而对…

【小米的技术分享】拯救程序员的“救命稻草”:Git回滚命令大揭秘!

大家好&#xff0c;我是小米。作为一名热爱技术的程序员&#xff0c;经常使用Git进行版本控制是我们的家常便饭。但是&#xff0c;难免会遇到一些意外&#xff0c;比如不小心提交了错误的代码或者合并了错误的分支&#xff0c;这时候就需要用到Git回滚命令了。今天&#xff0c;…

chrome谷歌浏览器书签不同步的解决办法

背景&#xff1a;多台电脑使用时&#xff0c;发现浏览器书签并没有及时同步&#xff0c;找到最终的解决办法&#xff1a; 第1步&#xff1a;chrome地址栏中输入&#xff1a; chrome://sync-internals/ 第2步&#xff1a;点击 Disable Sync (Clear Data) 点击Request Start 第3…

马上掌握的LayUI树形权限菜单,助力你的权限管理!

目录 一、树形菜单的介绍 1、什么是树形菜单&#xff1f; 二、实现思路流程 三、实现步骤 1、查看数据 1&#xff09;表数据 2&#xff09; 最终效果 2、编程 1&#xff09;实体类编写 2&#xff09;PermissionDao编写&#xff08;难点&#xff09; 第一 在线转json…

vue+springboot基于Web的电子产品销售系统设计与实现 gqon2a

随着人们生活水平的高速发展&#xff0c;电子产品销售方面在近年来呈直线上升&#xff0c;人们也了解到电子产品的实用性&#xff0c;因此电子产品的销售数量也逐年递增&#xff0c;电子产品销售的增加加大了在管理上的工作难度。为了能更好的维护电子产品销售管理秩序&#xf…

Grafana 图形面板定制方案

Grafana 在一个 Panel 中添加多数据源同时展示以及修改通过 transform 修改图表图例的方式。 多个数据在一个折线图中 在 Grafana 中我们可能会希望多个数据在一个Panel 中展示&#xff0c;比如&#xff1a; 通过编辑 Panel 增加 Query 数据我们即可做到&#xff1a;像上面中…

SQL数据库连接类型与常用函数

目录 1. 创建表插入数据 2. 连接类型 2.1 内连接 2.2 外连接 2.2.1 左外连接 2.2.2 右外连接 2.3 交叉连接 2.4 子查询&公用表达式 2.5 UNION连接 3. SQL常用函数 3.1 CASE WHEN函数 3.2 COALESCE函数 3.3 NULLIF函数 3.4 LEAST 和 GREATEST函数 3.5 DISTINCT…

LayUi之树形结构的详解(附有全案例代码)

&#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 接下来看看由辉辉所写的关于LayUi的相关操作吧 目录 &#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 一. 什么是树形结构 二.树形结构在什么时…

表格编程之争:Python VS VBA?Excel用户:新编程语言才真香

Python和VBA哪个更好用&#xff1f; Python和VBA是两种不同的编程语言&#xff0c;它们都有自己的特点和优缺点。在表格编程方面&#xff0c;VBA在Excel中的应用非常广泛&#xff0c;可以通过宏来实现自动化操作和数据处理&#xff0c;也可以通过VBA代码来实现自定义函数和界面…

python qt安装软件包

安装 opencv pip install opencv-python -i https://pypi.tuna.tsinghua.edu.cn/simple/ 安装pyqt5 pip install pyqt5 -i https://pypi.tuna.tsinghua.edu.cn/simple/ 安装pyqt5-tools pip install pyqt5-tools -i https://pypi.tuna.tsinghua.edu.cn/simple/

RLHF-基于人类反馈的强化学习

RLHF 文章目录 RLHF强化学习基础回顾为什么要使用基于人类反馈的强化学习大纲RLHF的起源大预言模型中的RLHF案例 ChatGPT RLHF中的技术细节预训练语言模型训练奖励模型基于RL进行微调 RLHF 的未来 强化学习基础回顾 智能体通过采取行动与环境进行交互&#xff0c;并返回状态和奖…

【C语言督学营 第十八天】考研408排序大题初探(将排序思想融入题目)

文章目录 题目一分析代码实战 题目二分析代码实战 补充(快排与归并)数据结构大题注意点&#xff01;&#xff01;&#xff01;(评分标准) 题目一 分析 (1&#xff09;算法的基本设计思想 由题意知&#xff0c;将最小的nl2个元素放在Ai中&#xff0c;其余的元素放在A2中&#x…