当前位置: 首页 > news >正文

[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);

相关文章:

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

C语言的宏系统相当强大,它允许使用##符号来处理预处理期的文本替换。这种用法被称为标记连接(token pasting)操作,其结果是将两个标记紧紧地连接在一起,而省略掉它们之间的所有空格。在复杂的宏定义中,运用…...

基于语音识别的智能电子病历(五)电子病历编辑器

前言 首先我们要明确一个概念:很多电子病历的编辑器,在输入文字的地方,有个麦克风按钮,点击一下,可以进行录音,然后识别的文字会自动输入到电子病历中,这种方式其实不能称为“基于语音识别的智…...

云计算技术高速发展,优势凸显

云计算是一种分布式计算技术,其特点是通过网络“云”将巨大的数据计算处理程序分解成无数个小程序,并通过多部服务器组成的系统进行处理和分析这些小程序,最后将结果返回给用户。它融合了分布式计算、效用计算、负载均衡、并行计算、网络存储…...

文本三剑客其二

文本三剑客其二 sed和awk grep就是查找文本当中的内容,扩展正则表达式。 sed 对文本内容进行增删改查 sed是一种流编辑器,一次处理一行内容。 如果只是展示,会放在缓冲区(模式空间),展示结束之后&…...

【达梦数据库】typeorm+node.js+达梦数据库返回自增列值

1.配置环境,下载依赖包 typeorm init --name test22 --database mysql typeorm-dm,uuid,typeorm2,修改连接信息 修改src/ data-source.ts 文件 连接dm,可参考刚刚安装typeorm-dm 模块中的 README.md 3.修改自增信息 /* 修改前*/PrimaryGen…...

【ARMv8/ARMv9 硬件加速系列 2.1 -- ARM NEON 向量寄存器单个元素赋值】

文章目录 NEON 向量寄存器单个元素赋值对 v0.4s中的一个元素赋值对 v1.16b 中的一个元素赋值MOVI (Move Immediate)NEON 向量寄存器单个元素赋值 在ARMv8架构中,你可以使用特定的指令来对v0.4s和v1.16b中的单个元素赋值。这通常通过使用MOV(Move)指令的变种实现,具体取决于…...

GD32学习

参考视频13.立创开发板GD32教程:串口配置_哔哩哔哩_bilibili 固件库跟用户手册基本上差不多,只不过用用户手册编写程序的话会更加的底层,固件库的话就是把一些函数封装起来,用的时候拿过来即可,目前我还没有找到固件库…...

LangChain:如何高效管理 LLM 聊天历史记录?

LangChain 团队发布了一篇关于使用 Dragonfly DB 来有效管理 LangChain 应用程序聊天历史记录的教程。 该教程旨在解决用户在使用 LangChain 应用程序时普遍遇到的一个问题:如何高效地管理聊天历史记录。 LangChain 团队在推文中强调了 Dragonfly DB 在管理聊天历…...

【React】useState 更新延迟的原因是什么,怎么解决?

useState 更新延迟的原因 异步更新:React 中的 useState 更新是异步的,这意味着当你调用更新函数(如 setData)时,React 并不立即同步更新状态,而是将其放入一个待处理的队列中,稍后在适当的时候(如在下一次渲染之前)进行处理。因此,如果你尝试在调用更新函数后立即读…...

非关系型数据库NoSQL数据层解决方案 之 redis springboot整合与读写操作 2024详解以及window版redis5.0.14下载百度网盘

redis下载安装以及基本使用 下载地址 链接:百度网盘 请输入提取码 提取码:0410 一个名对应一个数值 内存级 在内存里进行操作 准备启动 我们现在就有一个redis客户端的服务器了 我们再启动一个cmd 操作redis数据库 redis里面的基本数据类型有五种 …...

jigdo无法下载的文件

问题描述 用jigdo下载Debian的iso镜像,剩下最后一个文件下载不了,提示信息: Found 0 of the 1 files required by the template Copied input files to temporary file debian-12.5.0-amd64-DLBD-2.iso.tmp - repeat command and supply mo…...

C#面:C# 类的执行顺序?

C# 类的执行顺序可以分为以下几个步骤: 静态字段初始化:在类的第一次使用之前,静态字段会被初始化。静态字段的初始化顺序是按照它们在代码中的声明顺序进行的。静态构造函数:如果类中定义了静态构造函数,它会在类的第…...

昇思25天学习打卡营第3天|数据集Dataset

一、简介: 数据是深度学习的基础,高质量的数据输入将在整个深度神经网络中起到积极作用。有一种说法是模型最终训练的结果,10%受到算法影响,剩下的90%都是由训练的数据质量决定。(doge) MindSpore提供基于…...

SpringCloud 服务调用 spring-cloud-starter-openfeign

在Spring Cloud中,spring-cloud-starter-openfeign 是一个用于声明式Web服务客户端(例如REST客户端)的启动器。它使得在Spring Cloud应用中调用其他HTTP服务变得非常简单,只需创建一个接口并使用注解来定义服务调用的细节。 以下…...

基于Elementui组件,在vue中实现多种省市区前端静态JSON数据展示并支持与后端交互功能,提供后端名称label和id

基于Elementui组件,在vue中实现多种省市区前端静态数据(本地JSON数据)展示并支持与后端交互功能,提供后端名称label和id 话不多说,先上图 1.支持传递给后端选中省市区的id和名称,示例非常完整&#xff0c…...

基于DPU的云原生裸金属网络解决方案

1. 方案背景和挑战 裸金属服务器是云上资源的重要部分,其网络需要与云上的虚拟机和容器互在同一个VPC下,并且能够像容器和虚拟机一样使用云的网络功能和能力。 传统的裸金属服务器使用开源的 OpenStack Ironic 组件,配合 OpenStack Neutron…...

pip install镜像源(更新和换源)

pip install镜像源(更新和换源) 1.pip安装依赖包默认访问的源: 因为服务器架设在国外的缘故,很多时候不好用网速不行,这时候就需要选择国内的一些安装源安装相应的包 https://pypi.Python.org/simple/2.设置默认源 …...

基础语法——组合与继承

继承 定义派生类,即继承的一般语法结构如下 class 派生类名 : [继承方式] 基类名 { }; 例如 class Point{int x, y; public:Point(int a0, int b0): x(a), y(b){}virtual double area() {return 0.0; };virtual double volume() { return 0.0; } }; class Circl…...

openGauss开发者大会、华为云HDC大会举行; PostgreSQL中国技术大会7月杭州开启

重要更新 1. openGauss Developer Day本周五于北京举行,大会聚集了相关行业专家、用户、伙伴和开发者,分享给予openGauss的联合创新成果和实践案例。([2] ) ;华为云 HDC 2024本周五于东莞松山湖举行,主题演讲主要覆盖鸿蒙、AI ([3…...

编译报错:No rule to make target xx/libcam.halmemory_intermediates/export_includes

问题现象: make: *** No rule to make target ‘out/target/product/testdd6737m_35g_m0/obj/STATIC_LIBRARIES/libcam.halmemory_intermediates/export_includes’, needed by ‘out/target/product/testdd6737m_35g_m0/obj/SHARED_LIBRARIES/libcam_platform_inte…...

从WWDC看苹果产品发展的规律

WWDC 是苹果公司一年一度面向全球开发者的盛会,其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具,对过去十年 WWDC 主题演讲内容进行了系统化分析,形成了这份…...

Python实现prophet 理论及参数优化

文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候,写过一篇简单实现,后期随着对该模型的深入研究,本次记录涉及到prophet 的公式以及参数调优,从公式可以更直观…...

P3 QT项目----记事本(3.8)

3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...

Python爬虫(一):爬虫伪装

一、网站防爬机制概述 在当今互联网环境中&#xff0c;具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类&#xff1a; 身份验证机制&#xff1a;直接将未经授权的爬虫阻挡在外反爬技术体系&#xff1a;通过各种技术手段增加爬虫获取数据的难度…...

是否存在路径(FIFOBB算法)

题目描述 一个具有 n 个顶点e条边的无向图&#xff0c;该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序&#xff0c;确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数&#xff0c;分别表示n 和 e 的值&#xff08;1…...

html-<abbr> 缩写或首字母缩略词

定义与作用 <abbr> 标签用于表示缩写或首字母缩略词&#xff0c;它可以帮助用户更好地理解缩写的含义&#xff0c;尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时&#xff0c;会显示一个提示框。 示例&#x…...

基于 TAPD 进行项目管理

起因 自己写了个小工具&#xff0c;仓库用的Github。之前在用markdown进行需求管理&#xff0c;现在随着功能的增加&#xff0c;感觉有点难以管理了&#xff0c;所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD&#xff0c;需要提供一个企业名新建一个项目&#…...

LangChain知识库管理后端接口:数据库操作详解—— 构建本地知识库系统的基础《二》

这段 Python 代码是一个完整的 知识库数据库操作模块&#xff0c;用于对本地知识库系统中的知识库进行增删改查&#xff08;CRUD&#xff09;操作。它基于 SQLAlchemy ORM 框架 和一个自定义的装饰器 with_session 实现数据库会话管理。 &#x1f4d8; 一、整体功能概述 该模块…...

Qemu arm操作系统开发环境

使用qemu虚拟arm硬件比较合适。 步骤如下&#xff1a; 安装qemu apt install qemu-system安装aarch64-none-elf-gcc 需要手动下载&#xff0c;下载地址&#xff1a;https://developer.arm.com/-/media/Files/downloads/gnu/13.2.rel1/binrel/arm-gnu-toolchain-13.2.rel1-x…...

SQL Server 触发器调用存储过程实现发送 HTTP 请求

文章目录 需求分析解决第 1 步:前置条件,启用 OLE 自动化方式 1:使用 SQL 实现启用 OLE 自动化方式 2:Sql Server 2005启动OLE自动化方式 3:Sql Server 2008启动OLE自动化第 2 步:创建存储过程第 3 步:创建触发器扩展 - 如何调试?第 1 步:登录 SQL Server 2008第 2 步…...