[ARM-2D 专题]3. ##运算符

在这里插入图片描述

C语言的宏系统相当强大,它允许使用##符号来处理预处理期的文本替换。这种用法被称为标记连接(token pasting)操作,其结果是将两个标记紧紧地连接在一起,而省略掉它们之间的所有空格。在复杂的宏定义中,运用##可以有效地生成新的标识符或调整代码的结构。对##符号的深入理解可以帮助编写出更高效、更灵活的代码,但同时也需要注意其可能带来的复杂性和可读性问题。

##运算符,也叫连接运算符(也称胶水运算符),预处理程序把出现在##两侧的参数合并成一个符号,通常用于宏参数的连接。

  1. 基本应用:
    将两个符号连接到一起。
#define ARM_CONNECT(__A, __B)                        __A##__B

//如下方式使用这个宏:
	int ARM_CONNECT(int,5;
//最终被展开为:
   int int5;
#define uint16Array(name,size) uint16_t  Array##name[size];
//如下方式使用这个宏:
	uint16Array(UartTx,128;
//最终被展开为:
   uint16_t  ArrayUartTx[128];

说明:
Array与name是没有天然的分割的,要将Array于name所代表的内容粘结在一起,就需要使用“##”运算符的帮助。
name与“[”具有天然分隔的,编译器不会认为"name"与"[“是连接在一起的,因此这里并不需要使用”##"运算符,如果你这么做了,预编译器会毫不犹豫的告诉你语法错误。
2. 基于C99的扩展应用
一般应用于带可变参数的宏定义中,比如:

//如下宏定义:
#define log(__STRING, ...)    printf(__STRING, __VA_ARGS__)
//我们调用:
log("output\r\n");
log(" Cycle Count : %d", total_cycle_cnt);
//会被展开为:
printf("output\r\n",);
printf(" Cycle Count : %d", total_cycle_cnt);

看似没有问题,注意到一个细节没有?在第一个printf()的最后多了一个",“。虽然有些编译器,例如GCC并不会计较(也许就是一个warning),但是在ANSI-C99标准引入可变参数宏的时候,又贴心了加了一个不那么起眼的语法:当下面的组合出现时 (”,##VA_ARGS"),如果__VA_ARGS__是一个空字符串,则前面的逗号","会一并被删除掉。因此,上面的宏可以改写为:

//如下宏定义:
#define log(__STRING, ...)    printf(__STRING, ##__VA_ARGS__)
//我们调用:
log("output\r\n");
log(" Cycle Count : %d", total_cycle_cnt);
//会被展开为:
printf("output\r\n"); //无可变参数,没有后面的逗号了
printf(" Cycle Count : %d", total_cycle_cnt); //有参数,逗号依旧存在
  1. 结合逗号表达式和##连接符的高级应用
    我们看arm-2d里面大量使用了这种特征,用来给函数提供初始化默认参数。如下:
//定义一个宏
#define arm_2d_scene_watch_init(__DISP_ADAPTER_PTR, ...)                    \
            __arm_2d_scene_watch_init((__DISP_ADAPTER_PTR), (NULL, ##__VA_ARGS__))
//函数的原型
extern user_scene_watch_t *__arm_2d_scene_watch_init(   arm_2d_scene_player_t *ptDispAdapter, 
                                        user_scene_watch_t *ptScene);
//调用
   arm_2d_scene_watch_init(&DISP0_ADAPTER);
//宏被替换为:
	__arm_2d_scene_watch_init(&DISP0_ADAPTER,NULL); //增加了一个默认参数NULL

如上的代码,在使用宏arm_2d_scene_watch_init的时候,只传递了一个参数,但是最终替换后自动增加了一个参数。怎么做到的呢?
看看逗号表达式: (NULL, ##VA_ARGS)
第一种情况:
__VA_ARGS__为空,那么这个表达是的值就是NULL。
第二种情况:
__VA_ARGS__为非空,那么这个表达的值就是可变参数传递进来的值。

比如,带第二个参数的调用:

//调用
   arm_2d_scene_watch_init(&DISP0_ADAPTER,&buffer);
//宏被替换为:
	__arm_2d_scene_watch_init(&DISP0_ADAPTER,&buffer);

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

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

相关文章

数组元素的内存地址计算【数据结构与算法C#版】

数组元素被存储在连续的内存空间中,这意味着计算数组元素的内存地址非常容易。给定数组内存地址(首 元素内存地址)和某个元素的索引,我们可以使用下方图 所示的公式计算得到该元素的内存地址,从而直接 访问该元素。 观…

探索CSS clip-path: polygon():塑造元素的无限可能

在CSS的世界里,clip-path 属性赋予了开发者前所未有的能力,让他们能够以非传统的方式裁剪页面元素,创造出独特的视觉效果。其中,polygon() 函数尤其强大,它允许你使用多边形来定义裁剪区域的形状,从而实现各…

【C语言】排序算法 -------- 计数排序

个人主页 创作不易,感谢大家的关注! 文章目录 1. 计数排序的概念2. 计数排序使用场景3. 计数排序思想4. 计数排序实现过程5. 计数排序的效率6. 总结(附源代码) 1. 计数排序的概念 计数排序是一种非比较的排序算法,其…

二、交换机介绍及vlan原理

目录 一、交换机 1.1、交换机处理数据帧的三种行为 1.2、初始化通信 二、虚拟局域网(VLAN) 三、vlan间通信 3.1、子接口 3.2、三层交换机 一、交换机 交换机:隔离冲突域,交换机每个接口都有一个网卡&#…

解放代码:识别与消除循环依赖的实战指南

目录 一、对循环依赖的基本认识 (一)代码中形成循环依赖的说明 (二)无环依赖的原则 二、识别和消除循环依赖的方法 (一)使用JDepend识别循环依赖 使用 Maven 集成 JDepend 分析报告识别循环依赖 &a…

超越中心化:Web3如何塑造未来数字生态

随着技术的不断发展,人们对于网络和数字生态的期望也在不断提升。传统的中心化互联网模式虽然带来了便利,但也暴露出了诸多问题,比如数据滥用、信息泄露、权力集中等。在这样的背景下,Web3技术应运而生,旨在打破传统中…

Shopee API接口:获取搜索栏生成的商品结果列表

一、平台介绍 Shopee,作为东南亚领先的电商平台,一直致力于为卖家和买家提供便捷、高效的在线购物体验。为了满足广大开发者的需求,Shopee提供了丰富的API接口服务,帮助卖家和第三方开发者更好地与平台进行数据交互,实…

ucos抢占式实时多任务操作系统 (RTOS)。

介绍 uCOS (也称为 μC/OS 或 Micro-Controller Operating System) 是一个开源的、可移植的、可裁剪的、抢占式实时多任务操作系统 (RTOS)。它最初由 Jean J. Labrosse 编写,并广泛用于嵌入式系统设计中。uCOS 是一个小型的 RTOS,非常适合那些需要实时性…

区间预测 | Matlab实现CNN-ABKDE卷积神经网络自适应带宽核密度估计多变量回归区间预测

区间预测 | Matlab实现CNN-ABKDE卷积神经网络自适应带宽核密度估计多变量回归区间预测 目录 区间预测 | Matlab实现CNN-ABKDE卷积神经网络自适应带宽核密度估计多变量回归区间预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab实现CNN-ABKDE卷积神经网络自适应…

基于深度学习网络的USB摄像头实时视频采集与人脸检测matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 将摄像头对这播放视频的显示器,然后进行识别,识别结果如下: 本课题中,使用的USB摄像头为&#xff…

30.保存游戏配置到文件

上一个内容:29.添加录入注入信息界面 以 29.添加录入注入信息界面 它的代码为基础进行修改 效果图: 首先在我们辅助程序所在目录下创建一个ini文件 文件内容 然后首先编写一个获取辅助程序路径的代码 TCHAR FileModule[0x100]{};GetModuleFileName(NUL…

【教学类-12-12】20240617通义万相-动物图片6张编故事(A4一页4条)

背景需求 【教学类-12-11】20240612通义万相-动物图片连连看(A4一页3套)-CSDN博客文章浏览阅读891次,点赞34次,收藏11次。【教学类-12-11】20240612通义万相-动物图片连连看(A4一页3套)https://blog.csdn.n…

Web前端项目-拼图游戏【附源码】

拼图游戏 拼图游戏是一种经典的益智游戏,通过HTML、CSS和JavaScript等前端技术的综合运用来实现;拼图游戏可以锻炼玩家的观察能力、空间认知能力和逻辑思维能力。游戏开始时,一张图片会被切割成多个小块,并以随机顺序排列在游戏区…

【第三篇】SpringSecurity请求流程分析

简介 本篇文章主要分析一下SpringSecurity在系统启动的时候做了那些事情、第一次请求执行的流程是什么、以及SpringSecurity的认证流程是怎么样的,主要的过滤器有哪些? SpringSecurity初始化流程 1.加载配置文件web.xml 当Web服务启动的时候,会加载我们配置的web.xml文件…

你是否感受到AI就在身边?

人工智能(AI)是一项革命性的技术,旨在模仿人类智慧并执行通常需要人类认知能力的任务。它覆盖了多个子领域,如机器学习、自然语言处理、计算机视觉和机器人技术。AI系统设计用于分析大量数据、从模式中学习、做出预测,…

ue5创建地图瓦片

先在虚幻商城下载免费的paperzd插件,并启用。 导入资源后,先通过应用paper2d纹理资源,将去掉导入ue时产生的边缘模糊,再点击下面的创建瓦片集, 打开瓦片集,发现选中不对, 改变瓦片大小为16*…

Java——IO流(字符流,字节流)

JavaIO的整体框架图 IO流从方向上来说,可以分为输入流和输出流; 从传输内容上来说,可以分为字符流和字节流 防止记混的口诀 所谓的IO,说白了就是数据在内存和硬盘之间的传输 输入流 %Reader %InputStream,从硬盘写…

如何应对缺失值带来的分布变化?探索填充缺失值的最佳插补算法

本文将探讨了缺失值插补的不同方法,并比较了它们在复原数据真实分布方面的效果,处理插补是一个不确定性的问题,尤其是在样本量较小或数据复杂性高时的挑战,应选择能够适应数据分布变化并准确插补缺失值的方法。 我们假设存在一个…

华为----RIP- RIPv2的认证配置

8.2 配置RIPv2的认证 8.2.1 原理概述 配置协议的认证可以降低设备接受非法路由选择更新消息的可能性,也可称为“验证”。非法的更新消息可能来自试图破坏网络的攻击者,或试图通过欺骗路由器发送数据到错误的目的地址的方法来捕获数据包。RIPv2协议能够…

Pycharm社区版搭建Django环境及Django简单项目、操控mysql数据库

Web应用开发(Django) 一、配置Django环境 1、先通过Pycharm社区版创建一个普通的项目 2、依次点击”file"-->"Settings" 3、点击"Project:项目名"-"Python Interpreter"-"号" 4、在搜索框输入要安装的…