Advanced Macro Techniques in C/C++: `#`, `##`, and Variadic Macros
Advanced Macro Techniques in C/C++: #
, ##
, and Variadic Macros
文章目录
- Advanced Macro Techniques in C/C++: `#`, `##`, and Variadic Macros
- Illustrative Examples of Macros Using `#` and `##`
- Stringification Example
- Token Concatenation Example
- Nested Macros Example
- Key Concepts of Nested Macros
- Macro Expansion Rules
- Operators in Macro Definitions
- Challenges with `#` and `##`
- Detailed Example
- Example of Nested Macro Expansion
- Direct Expansion Example
- Why Use Nested Macros?
- Variable Argument Macros (Variadic Macros)
- Explanation
- Summary
Date | Author | Version | Note |
---|---|---|---|
2024-12-02 | Tao | V1.0 | Finish the document. |
Macros are an integral component of the C/C++ preprocessor, enabling the definition of reusable code fragments that enhance flexibility and abstraction. The #
and ##
operators are powerful tools used within macros for stringification and token concatenation, respectively. A deep understanding of these operators, particularly in nested contexts, allows for more sophisticated and reliable macro behavior.
The use of nested macros is a common technique in C and C++ to perform operations like token stringification or concatenation effectively through preprocessor directives. Mastering the behavior of macros when utilizing #
(stringification) or ##
(token concatenation) operators ensures that arguments are appropriately expanded, even when these arguments themselves involve other macro definitions.
Illustrative Examples of Macros Using #
and ##
Stringification Example
#define Stringify(A) #A
printf("%s\n", Stringify(Hello)); // Output: "Hello"
Here, the #
operator is used to convert the argument Hello
into a string literal.
Token Concatenation Example
#define Concat(A, B) A##B
int HelloWorld = 5;
printf("%d\n", Concat(Hello, World)); // Output: 5
The ##
operator concatenates Hello
and World
into a single token, HelloWorld
.
Nested Macros Example
#define Outer(A) Inner(A)
#define Inner(A) #A
printf("%s\n", Outer(Hello)); // Output: "Hello"
By using nested macros, the argument is fully expanded before the stringification operation is applied.
Key Concepts of Nested Macros
Macro Expansion Rules
- Macros in C are expanded in a single pass unless explicitly nested within other macros.
- If a macro’s argument includes another macro, the preprocessor does not expand the inner macro unless explicitly instructed through an additional macro layer.
Operators in Macro Definitions
#
: Converts a macro argument into a string literal.##
: Concatenates two tokens into one.
Challenges with #
and ##
When using #
or ##
within a macro, the preprocessor suppresses the evaluation of macro arguments before applying the operator. This suppression ensures that #
or ##
acts on the exact tokens provided, requiring an additional layer of macro indirection to achieve the desired behavior.
Detailed Example
Consider the following macro definitions:
#define Stringify(A) _Stringify(A) // Outer macro
#define _Stringify(A) #A // Inner macro that performs stringification#define Concat(A, B) _Concat(A, B) // Outer macro
#define _Concat(A, B) A##B // Inner macro that performs concatenation
-
Stringify Macro:
Stringify(A)
passes its argumentA
to_Stringify(A)
._Stringify(A)
then applies the#
operator to convertA
into a string literal.
-
Concat Macro:
Concat(A, B)
passes its argumentsA
andB
to_Concat(A, B)
._Concat(A, B)
uses the##
operator to concatenateA
andB
.
Example of Nested Macro Expansion
Consider the following code:
printf("%s\n", Stringify(Concat(Hel, lo)));
-
Step 1: Expand
Stringify(Concat(Hel, lo))
:Stringify(A)
becomes_Stringify(A)
, whereA
isConcat(Hel, lo)
.- Result:
_Stringify(Concat(Hel, lo))
.
-
Step 2: Expand
_Stringify(Concat(Hel, lo))
:- Before applying the
#
operator, the macro argumentConcat(Hel, lo)
is expanded because it is passed through another macro layer. Concat(Hel, lo)
expands to_Concat(Hel, lo)
and subsequently toHello
(using the##
operator).- Result:
_Stringify(Hello)
.
- Before applying the
-
Step 3: Apply
_Stringify(Hello)
:- The
#
operator convertsHello
into a string literal. - Result:
"Hello"
.
- The
Output:
Hello
Direct Expansion Example
Consider the following code:
printf("%s\n", _Stringify(Concat(Hel, lo)));
- Step 1: Expand
_Stringify(Concat(Hel, lo))
:_Stringify(A)
directly applies the#
operator to the argumentConcat(Hel, lo)
without expanding it.- Result:
"Concat(Hel, lo)"
.
Output:
Concat(Hel, lo)
Why Use Nested Macros?
Nested macros ensure proper argument expansion before applying the #
or ##
operators. Without this nesting:
- The
#
operator would stringify the literal macro argument without expanding it. - The
##
operator would concatenate the original tokens rather than their expanded forms.
Variable Argument Macros (Variadic Macros)
Variadic macros allow for defining macros that accept a variable number of arguments. This feature is particularly advantageous for flexible logging or debugging macros.
Consider the following example:
#define Log(format, ...) printf(format, ##__VA_ARGS__)
Explanation
Log(format, ...)
defines a macro that accepts a format string and a variable number of additional arguments.__VA_ARGS__
is a special placeholder for the variable arguments.##__VA_ARGS__
is used to handle the case where no additional arguments are provided, preventing a trailing comma error.
Usage Example:
Log("Error: %s, Code: %d\n", "File not found", 404); // Output: Error: File not found, Code: 404
Log("Simple message\n"); // Output: Simple message
Summary
- Utilize nested macros when dealing with macro arguments involving other macros and the
#
or##
operators. - The outer macro ensures arguments are fully expanded before being processed by the inner macro.
- Variadic macros (
...
and__VA_ARGS__
) provide the ability to create macros that accommodate a variable number of arguments, enhancing code flexibility and readability.
These examples illustrate the critical importance of proper macro usage:
- With Nested Macros:
Stringify(Concat(Hel, lo))
correctly expands to"Hello"
. - Without Nested Macros:
_Stringify(Concat(Hel, lo))
results in"Concat(Hel, lo)"
due to the lack of proper expansion. - Variadic Macros: Provide a powerful mechanism for managing functions like logging without manual adjustments for the number of arguments.
相关文章:
Advanced Macro Techniques in C/C++: `#`, `##`, and Variadic Macros
Advanced Macro Techniques in C/C: #, ##, and Variadic Macros 文章目录 Advanced Macro Techniques in C/C: #, ##, and Variadic MacrosIllustrative Examples of Macros Using # and ##Stringification ExampleToken Concatenation ExampleNested Macros Example Key Conc…...

Maven、JAVAWeb、Servlet
知识点目标 1、MavenMaven是什么Maven项目的目录结构Maven的Pom文件Maven的命令Maven依赖管理Maven仓库JavaWeb项目 2.网络基础知识 3、ServletMaven Maven是什么 Maven是Java的项目管理工具,可以构建,打包,部署项目,还可以管理…...

分布式资源调度——yarn 概述(资源调度基本架构和高可用的实现)
此文章是学习笔记,图片均来源于B站:哈喽鹏程 yarn详细介绍 1、yarn 简介1.1 yarn的简介1.2 yarn 的基本架构1.3. yarn 的高可用 2、yarn 调度策略、运维、监控2.1 yarn 的调度策略2.1.1 FIFO scheduler(先进先出)2.1.2 容量调度2.1.3 公平调度 2.2 yarn…...

网页开发的http基础知识
请求方式-GET:请求参数在请求行中,没有请求体,如:/brand/findAll?nameoPPo&status1。GET请求大小在浏览器中是有限制的请求方式-POST:请求参数在请求体中,POST请求大小是没有限制的 HTTP请求…...
学习方法的进一步迭代————4
今天又在怀疑第二大脑的可靠程度 为什么呢? 还是因为自己没记住东西,感觉没学到东西。 其实自己知道大脑本就不应该用来存放知识而是用来思考知识,但是自己还是陷在里面了,我觉得其本质不是因为认知还不够,也不是因为还有点不适…...

数据科学家创建识别假图像的工具
Pixelator v2 是一款用于识别假图像的工具。它采用了全新的图像真实性技术组合,其能力超出了人眼所能看到的范围。 它能够以比传统方法更高的准确度识别图像中的细微差异,并且已被证明能够检测到小至 1 个像素的交替。 使用 SSIM 和 Pixelator v2 突出显…...

使用 GORM 与 MySQL 数据库进行交互来实现增删改查(CRUD)操作
1、安装 GORM 和 MySQL 驱动 新版本库是gorm.io/gorm go get -u gorm.io/gormgo get -u gorm.io/driver/mysql2、连接 MySQL 数据库 package mainimport ("gorm.io/driver/mysql""gorm.io/gorm""log" )func main() {// 数据源名称 (DSN) 格式&a…...

Day2 生信新手笔记: Linux基础
一、基础知识 1.1 服务器 super computer 或 server 1.2 组学数据分析 组学数据:如基因组学、转录组学、蛋白质组学等; 上游分析:主要涉及原始数据的获取和初步处理,计算量大,消耗的资源较多,在服务器完…...

001集—— 创建一个WPF项目 ——WPF应用程序入门 C#
本例为一个WPF应用(.NET FrameWork)。 首先创建一个项目 双击xaml文件 双击xaml文件进入如下界面,开始编写代码。 效果如下: 付代码: <Window x:Class"WpfDemoFW.MainWindow"xmlns"http://schema…...
【C++】1___引用
一、基本语法 数据类型 &别名 原名 #include<iostream> using namespace std; int main(){int a 10;int &b a;cout<<"a"<<a<<endl; // a10cout<<"b"<<b<<endl;// a10b 20;cout<<"a…...

如何通过 JWT 来解决登录认证问题
1. 问题引入 在登录功能的实现中 传统思路: 登录页面时把用户名和密码提交给服务器服务器验证用户名和密码,并把检验结果返回给后端如果密码正确,则在服务器端创建 session,通过 cookie 把 session id 返回给浏览器 但是正常情…...

高效集成:将聚水潭数据导入MySQL的实战案例
聚水潭数据集成到MySQL:店铺信息查询案例分享 在数据驱动的业务环境中,如何高效、准确地实现跨平台的数据集成是每个企业面临的重要挑战。本文将聚焦于一个具体的系统对接集成案例——将聚水潭的店铺信息查询结果集成到MySQL数据库中,以供BI…...

Jenkins-基于 JNLP协议的 Java Web 启动代理
在上一篇的基础配置上进行以下步骤 工作流程: 通过 JNLP 启动代理,客户端从 Jenkins 服务器上下载一个 agent.jar 文件。该文件启动时,代理程序通过 JNLP 协议连接到 Jenkins 主节点。一旦连接成功,代理节点就可以执行从主节点分…...

Qt数据库操作-QSqlQueryModel 的使用
QSqlQueryModel 功能概述 QSqlQueryModel 是 QSqlTableModel 的父类。QSqlQueryModel 封装了执行 SELECT 语句从数据库查询数据的功能,但是 QSqlQueryModel 只能作为只读数据源使用,不可以编辑数据。QSqlQueryModel 类的主要函数如下: 接口…...
C语言编程1.21波兰国旗问题
题目描述 桌上有 n ( 1 < n < 10000 ) 面小旗,一部分是白旗,一部分是红旗(波兰国旗由白色和红色组成)。唯一允许的操作是交换两面小旗位置。请你设计一个算法,用最少的交换操作将所有的白旗都置于红旗的之前。 输入格式 第一行为一个…...

如何利用微型5G网关为智慧无人矿车提供精确定位
随着5G、AI、物联网技术的发展和普及,越来越多行业正在加快生产、运营、管理的无人化、数字化与智能化,以适应当前我国“智慧、绿色、低碳”的新型发展模式需要。其中矿产业就是典型场景之一。针对矿山场景的智慧化、无人化转型,佰马提供基于…...

使用docker-compese部署SFTPGo详解
官网:SFTP & FTP as a Managed Service (SaaS) and On-premise 一、SFTPGo简介 SFTPGo 是一款功能强大的文件传输服务器软件。它支持多种协议(SFTP、SCP、FTP/S、WebDAV、HTTP/S)和多个存储后端。 借助 SFTPGo,您可以利用本地…...

Ajax基础总结(思维导图+二维表)
一些话 刚开始学习Ajax的时候,感觉很模糊,但是好像学什么都是这样的,很正常,但是当你学习的时候要持续性敲代码,边敲代码其实就可以理解很多了。然后在最后的总结,其实做二维表之后,就可以区分…...

Spring Task和WebSocket使用
在现代 Web 应用中,WebSocket 作为一种全双工通信协议,为实时数据传输提供了强大的支持。若要确保 WebSocket 在生产环境中的稳定性和性能,使用 Nginx 作为反向代理服务器是一个明智的选择。本篇文章将带你了解如何在 Nginx 中配置 WebSocket…...

微信小程序 本地调试和vconsole可以 但在体验上页面不请求数据
微信小程序页面不请求数据 本地调试和vconsole可以 但在体验版页面不请求数据,如遇到这类问题基本都是一样的解决办法 1、如何调试找到问题 首先要把小程序本地设置的不校验合法域名关掉,不然本地一直都是好的 然后通过本地真机调试打断点找到问题位…...
变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析
一、变量声明设计:let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性,这种设计体现了语言的核心哲学。以下是深度解析: 1.1 设计理念剖析 安全优先原则:默认不可变强制开发者明确声明意图 let x 5; …...
synchronized 学习
学习源: https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖,也要考虑性能问题(场景) 2.常见面试问题: sync出…...

C++_核心编程_多态案例二-制作饮品
#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为:煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例,提供抽象制作饮品基类,提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...

盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...

为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?
在建筑行业,项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升,传统的管理模式已经难以满足现代工程的需求。过去,许多企业依赖手工记录、口头沟通和分散的信息管理,导致效率低下、成本失控、风险频发。例如&#…...

[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?
论文网址:pdf 英文是纯手打的!论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误,若有发现欢迎评论指正!文章偏向于笔记,谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...

图表类系列各种样式PPT模版分享
图标图表系列PPT模版,柱状图PPT模版,线状图PPT模版,折线图PPT模版,饼状图PPT模版,雷达图PPT模版,树状图PPT模版 图表类系列各种样式PPT模版分享:图表系列PPT模板https://pan.quark.cn/s/20d40aa…...

tree 树组件大数据卡顿问题优化
问题背景 项目中有用到树组件用来做文件目录,但是由于这个树组件的节点越来越多,导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多,导致的浏览器卡顿,这里很明显就需要用到虚拟列表的技术&…...
JAVA后端开发——多租户
数据隔离是多租户系统中的核心概念,确保一个租户(在这个系统中可能是一个公司或一个独立的客户)的数据对其他租户是不可见的。在 RuoYi 框架(您当前项目所使用的基础框架)中,这通常是通过在数据表中增加一个…...
Redis:现代应用开发的高效内存数据存储利器
一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发,其初衷是为了满足他自己的一个项目需求,即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源,Redis凭借其简单易用、…...