7.C语言 宏(Macro) 宏定义,宏函数

news2024/12/23 5:24:41

目录

宏定义

宏函数

1.注释事项

2.注意事项

宏(Macro)用法

常量定义

简单函数实现

类型检查

条件编译

宏函数计算参数个数

宏定义进行类型转换

宏定义进行位操作

宏定义进行断言

总结


宏定义

#include "stdio.h"
#include "string.h"
#include "stdlib.h"

#define MAX 1025 //定义宏

int main() 
{

	system("pause");
	return EXIT_SUCCESS;
}

宏函数

宏函数通常将一些比较频繁,短小的函数封装为宏函数。减少一些入栈,出栈的时间消耗。

在C语言中,宏(Macro)是预处理器的一种功能,它允许你定义一种简写形式来代替一段特定的代码。宏定义的基本形式如下:

#include "stdio.h"
#include "string.h"
#include "stdlib.h"

#define MYADD(x,y) x + y //宏函数

int main() 
{
	int a = 10;
	int b = 20;

	printf("a+b = %d\n",MYADD(a,b));
	system("pause");
	return EXIT_SUCCESS;
}

运行结果:

宏函数在预处理中做了一个替换 就是将 a 和 b替换成x和y。

宏函数是使用宏定义的函数风格的宏。它们可以像普通函数那样调用,但最终会被预处理器替换成相应的代码,减少入栈,出栈的时间。

1.注释事项

宏函数要保证运算的完整性才能执行,可以查看下面代码处理流程

#include "stdio.h"
#include "string.h"
#include "stdlib.h"

#define MYADD(x,y) x + y //宏函数

int main() 
{
	int a = 10;
	int b = 20;

	int result = MYADD(a, b) * 10;
	printf("result = %d\n", result);
	system("pause");
	return EXIT_SUCCESS;
}

打印结果

从上面结果来看,10 + 20 * 10 结果是等于300才符合我们预期,这个是运算完整性导致的。就是先乘除后加减问题

这个问题是可以解决的,通过()来处理,

#define MYADD(x,y) ((x) + (y)) //宏函数

2.注意事项

宏函数在一定的程度上会比普通的函数效率高

#include "stdio.h"
#include "string.h"
#include "stdlib.h"

#define MYADD(x,y) ((x) + (y)) //宏函数

void myAdd(int x,int y) { //x会在栈上定义,y也会 . 所以宏函数会有一定优势
	return x + y;
}

int main() 
{
	int a = 10;
	int b = 20;

	int result = MYADD(a, b) * 10;
	printf("result = %d\n", result);
	system("pause");
	return EXIT_SUCCESS;
}

可以从宏函数,和普通函数对比,一个没有栈的开销,一个有开销。

普通函数会有入栈和出栈时间上的开销

宏(Macro)用法

常量定义

#include "stdio.h"
#include "string.h"
#include "stdlib.h"

#define MAX 1024

int main() 
{

	printf("MAX = %d\n", MAX);
	system("pause");
	return EXIT_SUCCESS;
}

运行结果

有参数宏

#include "stdio.h"
#include "string.h"
#include "stdlib.h"

#define MYADD(x,y) ((x) + (y)) //宏函数


int main() 
{
	int a = 10;
	int b = 20;

	int result = MYADD(a, b);
	printf("result = %d\n", result);

	system("pause");
	return EXIT_SUCCESS;
}

运行结果:

宏运算链接符

#include "stdio.h"
#include "string.h"
#include "stdlib.h"

#define MAX 100
#define ROW 100
#define GET_MAX(x,y) \
x = x+y;\
y = x+y;

int main() 
{
	int a = 10;
	int b = 10;

	GET_MAX(a, b)

	printf("random %d  %d\n\n", a,b);
	system("pause");
	return EXIT_SUCCESS;
}

从上面代码来看\表示链接符号,运行完第一个,就执行第二个

 无参数宏

#include "stdio.h"
#include "string.h"
#include "stdlib.h"

#define MAX 100
#define ROW 100
#define RANDOM (-1.0 + 2.0*(double)rand() / RAND_MAX)

int main() 
{
	int v = 10;
	printf("random %lf\n\n",RANDOM);
	system("pause");
	return EXIT_SUCCESS;
}

类型检查

#include "stdio.h"
#include "string.h"
#include "stdlib.h"

#define CHECK_TYPE(a) generic((a), \
    int: printf("int"), \
    char: printf("char"), \
    float: printf("float"), \
    default: printf("other type") \
)

int main() 
{

	int v = 10;

	//CHECK_TYPE(v);
	printf("%s", _Generic(v));

	system("pause");
	return EXIT_SUCCESS;
}


条件编译

#include "stdio.h"
#include "string.h"
#include "stdlib.h"

#define DEBUG

#ifdef DEBUG
#define PRINT_DEBUG(fmt, ...) printf(fmt, ##__VA_ARGS__)
#else
#define PRINT_DEBUG(fmt, ...)
#endif

int main() 
{

	int v = 10;

	char value[] = "达帮主";

	PRINT_DEBUG("%s\n",value);

	system("pause");
	return EXIT_SUCCESS;
}

运行结果:

如果删掉define就不会有打印

宏函数计算参数个数

#define GET_MACRO(_1, _2, _3, _4, NAME, ...) NAME
#define VA_SIZE(...) \
    GET_MACRO(__VA_ARGS__, 4, 3, 2, 1, 0)
 
#define SHOW_PARAM_COUNT(...) \
    printf("Number of parameters: %d\n", VA_SIZE(__VA_ARGS__))
 
// 使用
SHOW_PARAM_COUNT(1, 2); // 输出:Number of parameters: 2

宏定义进行类型转换

#define CONTAINER_OF(ptr, type, member) \
    ((type *)((char *)(ptr) - (char *) &((type *)0)->member))

宏定义进行位操作

#define SET_BIT(x, bit) ((x) |= (1 << (bit)))
#define CLEAR_BIT(x, bit) ((x) &= ~(1 << (bit)))
#define FLIP_BIT(x, bit) ((x) ^= (1 << (bit)))
#define GET_BIT(x, bit) (((x) >> (bit)) & 1)

宏定义进行断言

#define ASSERT(expr) \
    if (!(expr)) { \
        printf("Assertion failed: %s\n", #expr); \
        exit(1); \
    }

总结

1.宏函数要保证运算的完整性。

2.宏函数在一定程度上,会比普通函数效率高,普通函数会有入栈和出栈时间上的开销。

3.通常会吧调用频繁的,短小的函数封装为宏函数。

4.宏函数的优点,以空间换时间。

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

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

相关文章

【LeetCode】906、超级回文数

【LeetCode】906、超级回文数 文章目录 一、通过数据量猜解法 枚举 数学 回文1.1 通过数据量猜解法 枚举 数学 回文1.2 多语言解法 二、打表法 一、通过数据量猜解法 枚举 数学 回文 1.1 通过数据量猜解法 枚举 数学 回文 减小数据规模: 先构成回文, 再平方, 再判断是否是范围…

SpringBoot的创建方式

SpringBoot创建的五种方式 1.通过Springboot官网链接下载 注意SpringBoot项目的封装方式默认为Jar 需要查看一下&#xff0c;自己的Maven版本是否正确 创建成功 2.通过 aliyun官网链接下载 修改服务路径为阿里云链接 创建成功 3.通过Springboot官网下载 点击&#xff0c;拉到最…

Android Studio AI助手---Gemini

从金丝雀频道下载最新版 Android Studio&#xff0c;以利用所有这些新功能&#xff0c;并继续阅读以了解新增内容。 Gemini 现在可以编写、重构和记录 Android 代码 Gemini 不仅仅是提供指导。它可以编辑您的代码&#xff0c;帮助您快速从原型转向实现&#xff0c;实现常见的…

物理信息神经网络(PINN)八课时教案

物理信息神经网络&#xff08;PINN&#xff09;八课时教案 第一课&#xff1a;物理信息神经网络概述 1.1 PINN的定义与背景 物理信息神经网络&#xff08;Physics-Informed Neural Networks&#xff0c;简称PINN&#xff09;是一种将物理定律融入神经网络训练过程中的先进方…

双臂机器人

目录 一、双臂机器人简介 二、双臂机器人系统的组成 三、双臂机器人面临的主要挑战 3.1 协调与协同控制问题 3.2 力控制与柔顺性问题 3.3 路径规划与轨迹优化问题 3.4 感知与环境交互 3.5 人机协作问题 3.6 能源与效率问题 3.7 稳定性与可靠性问题 四、双臂机器人…

日期区间选择器插件的操作流程

我们知道&#xff0c;在开发过程中&#xff0c;为了能够在规定时间内完成项目&#xff0c;有时候我们都会使用插件来大大提高我们的开发效率&#xff0c;有些插件是可以直接拿来用&#xff0c;但是有些插件拿过来之后是需要进行修改&#xff0c;在使用插件的时候还有很多的注意…

以ATTCK为例构建网络安全知识图

ATT&CK&#xff08;Adversarial Tactics, Techniques, and Common Knowledge &#xff09;是一个攻击行为知识库和模型&#xff0c;主要应用于评估攻防能力覆盖、APT情报分析、威胁狩猎及攻击模拟等领域。本文简单介绍ATT&CK相关的背景概念&#xff0c;并探讨通过ATT&a…

“年轻科技旗舰”爱玛A7 Plus正式发布,全国售价4999元

12月18日&#xff0c;备受行业瞩目的“A7上场 一路超神”爱玛旗舰新品发布会在爱玛台州智造工厂盛大举行。 作为年末“压轴产品”的“两轮豪华轿跑”爱玛A7Plus重磅上场&#xff0c;以“快、稳、帅、炫、智、爽”六大超神技惊艳四座&#xff0c;不仅践行了爱玛科技的精品战略&…

精通Redis(一)

目录 1.NoSQL 非关系型数据库 2.Redis 3.Redis的java客户端 4.Jedis 4.1Jedis快速入门 4.2Jedis连接池及使用 5.SpringDataRedis和RedisTemplate 1.NoSQL 非关系型数据库 基础篇-02.初始Redis-认识NoSQL_哔哩哔哩_bilibili NoSQL与SQL的区别就在于SQL是结构化的、关联…

研发效能DevOps: Vite 使用 Element Plus

目录 一、实验 1.环境 2.初始化前端项目 3.安装 vue-route 4.安装 pinia 5.安装 axios 6.安装 Element Plus 7.gitee创建工程 8. 配置路由映射 9.Vite 使用 Element Plus 二、问题 1.README.md 文档推送到gitee未自动换行 2.访问login页面显示空白 3.表单输入账户…

openbmc hwmon与sensor监控

1.说明 参考文档: https://github.com/openbmc/entity-manager/blob/master/docs/entity_manager_dbus_api.mdhttps://github.com/openbmc/entity-manager/blob/master/docs/my_first_sensors.md 1.1 简单介绍 注意: 本节是快速浏览整个sensor框架&#xff0c;了解大致open…

thinkphp框架diygw-ui-php进销存出库记录操作

将进销存的出库明细记录存储到数据库中&#xff0c;thinkphp框架diygw-ui-php后台通常涉及以下几个步骤&#xff1a; 数据库表定义 实现我们定义了三张表、一个产品表、出库订单表、出库订单产品明细表 生成API 进入DIY可视化API代码生成器&#xff0c;我们生成这三张表结应…

vertx idea快速使用

目录 1.官网下载项目 2.修改代码 2.1拷贝代码方式 为了能够快速使用&#xff0c;我另外创建一个新的maven项目&#xff0c;将下载项目的src文件和pom文件拷贝到新建的maven项目。 2.2删除.mvn方式 3.更新配置 4.配置application 5.idea启动项目 1.官网下载项目 从vert…

ComE(Community Embedding) -- 基于嵌入的社区检测优化算法

ComE&#xff08;Community Embedding&#xff09;是一种基于嵌入的社区检测优化算法。 它结合了节点嵌入技术与社区划分的目标&#xff0c;能够有效识别网络中的社区结构&#xff0c;并在社区划分过程中捕捉复杂的节点相互作用信息。 算法背景 传统的社区检测方法&#xff0c;…

CSS|14 z-index

z-index z-index表示谁压盖着谁&#xff0c;数值大的会压盖住数值小的。只有定位的元素才有z-index值&#xff0c;只有设置了固定定位、相对定位、绝对定位了的元素&#xff0c;才会拥有z-indexz-index的值是没有单位的&#xff0c;值是一个正整数&#xff0c;默认的z-index值…

重撸设计模式--代理模式

文章目录 定义UML图代理模式主要有以下几种常见类型&#xff1a;代理模式涉及的主要角色有&#xff1a;C 代码示例 定义 代理模式&#xff08;Proxy Pattern&#xff09;属于结构型设计模式&#xff0c;它为其他对象提供一种代理以控制对这个对象的访问。 通过引入代理对象&am…

vue中验证码的实现方式

在写登录页的时候有的系统会让你也进行一下验证码绘制&#xff0c;那么验证码如何实现的呢&#xff1f;我在写登录页的时候通过将登录框&#xff0c;验证码分开页面来写&#xff0c;最后将它们变成标签来导入到我的样式页面中&#xff0c;这样写不仅方便&#xff0c;更容易修改…

Spring(三)-SpringWeb-概述、特点、搭建、运行流程、组件、接受请求、获取请求数据、特殊处理、拦截器

文章目录 一、SpringWeb概述 二、SpringWeb特点 三、搭建SpringWeb&#xff08;在web项目中&#xff09; 1、导包 2、在web.xml文件中配置统一拦截分发器 DispatcherServlet 3、开启 SpringWEB 注解 4、处理器搭建 四、SpringWeb运行流程 五、SpringWeb组件 1、前端控…

构建MacOS应用小白教程(打包 签名 公证 上架)

打包 在package.json中&#xff0c;dependencies会被打进 Electron 应用的包里&#xff0c;而devDependencies则不会&#xff0c;所以必要的依赖需要放到dependencies中。files中定义自己需要被打进 Electron 包里的文件。以下是一个完整的 mac electron-builder的配置文件。 …

2.4 网络概念(分层、TCP)

网络层与传输层概述 网络层&#xff1a; 抽象概念&#xff1a;网络层是基于 IP 的抽象概念&#xff0c;与数据链路层用 MAC 地址标记设备不同。MAC 地址是一种具体化的概念&#xff0c;绑定于所在的物理网络&#xff0c;而 IP 地址可以是固定的&#xff0c;也可以通过路由动态…