C++中的间接宏函数
宏函数对于每个C++程序员都决不陌生,就算是初出茅庐的C++程序员也知道如何定义、使用宏函数。
但是当初学者看到类似于以下这种宏函数嵌套的时候,可能还是会比较嘀咕,
#define CONVERTSTR(x) #x
#define CONVERTSTR2(x) CONVERTSTR(x)
第二个宏函数所做的事情不就是再一次调用上面的宏函数吗,这难道不属于画蛇添足吗?这样做有什么意义呢?别急,我们慢慢来捋一下。
了解#和##
要想熟练的写出宏函数,了解其中的操作符必不可少,在预编译体系自定义的几个操作符中, #和##比较特殊,它们的作用是:
将标识符转换为字符串,它又被称为字符串化操作符,用法如下
#define CONVERTSTR(x) #x
string s3 { CONVERTSTR(4) }; //这里CONVERTSTR(4)被扩展为"4"
将不同的标识符连接起来,它被称为符号连接操作符,用法如下
struct ABC
{
};
#define DECLARE_MAKE(x) x* Make_##x() {return new x();}
DECLARE_MAKE(ABC) //被扩展为 ABC* Make_ABC{return new ABC();}
ABC * ap = Make_ABC();
可见这两操作符的运算结果取决于传入的标识符的名称,那么如果传入的标识符本身就是一个宏变量呢?
宏变量乱入的情况
还是刚刚的例子,
#define CONVERTSTR(x) #x
#define VAR 10
std::cout << CONVERTSTR(VAR);
猜猜,这个时候的输出是多少?10 还是 VAR?
按照预处理器替换的原则,VAR被替换成10,接着10被转换为"10",但是真是这样吗?
运行之后发现,输出是VAR不是10,为什么呢?
替换规则
这是因为当宏函数中,如果包含了#或者##,替换规则会比较特殊,引用一段原文如下:
After the arguments for the invocation of a function-like macro have been identified,
argument substitution takes place. A parameter in the replacement list, unless preceded by
a # or ## preprocessing token or followed by a ## preprocessing token (see below), is
replaced by the corresponding argument after all the macros contained therein have been
expanded. Before being substituted, each argument's preprocessing tokens are completely
macro replaced as if they formed the rest of the preprocessing file; no other preprocessing
tokens is available.
简而言之,对于宏函数来说,一般情况下当看到函数体的时候,参数替换就已经完成了(像用10替换VAR),但是对于有操作符#和##的参数,这个参数替换步骤就不会发生,所以CONVERTSTR(VAR)只会扩展为 "VAR"而不会扩展为"10"
修复方法
其实讲到这里答案已经很明显了,使用间接宏函数能完美解决这个问题
#define CONVERTSTR(x) #x
#define CONVERTSTR2(x) CONVERTSTR(x)
在原有函数的基础上再定义一个包装函数,这个包装函数并没有任何#或者##,这样就确保了参数可以正确展开,接着转发请求给真正需要使用的那个函数。
#define VAR 10
std::cout << CONVERTSTR2(VAR);
这样就能确保在使用VAR调用函数的时候它已经被正确展开了。
这就是间接宏函数和为什么要使用它们的原因,希望下次看到它们的时候不要再觉得这是画蛇添足了哟。
C++中的间接宏函数的更多相关文章
- C语言中宏定义与C++中的内联函数
一,宏定义:在预处理的时候把宏定义的内容替换到代码中,正常编译. 1,无参数宏定义和有参数宏定义 (1)宏定义不能加分号,比如:#define PI 3.24;错的,#define PI 3.24 ...
- FrameWork中SQLServer数据源使用宏函数出错解决办法
环境:DW是SQLServer2008 建模工具:Cognos FrameWork Version:Cognos10.2 出现问题:在FM中创建查询主题,sql类型数据源,引入宏函数#CAMIDLis ...
- FrameWork模型中引入宏函数报错解决方法
如下图在Framework的一个简单维度中加入宏函数 解决办法如下图 step1: step2: PS :Cognos 10.1.1中 在cognos connection中创建数据源,为什么没有od ...
- 【转】linux内核中writesb(), writesw(), writesl() 宏函数
writesb(), writesw(), writesl() 宏函数 功能 : writesb() I/O 上写入 8 位数据流数据 (1字节) writesw() I/O 上写入 16 ...
- IOS学习之路-- 指针&宏函数
如果*p被()包住,说明指针变量p将来指向的是函数 //声明一个指针变量 //int (*p)(int, int) = sum; int (*p)(int, int); p = sum; // 如果* ...
- 简答的理解C语言中的各种类型函数
1.变参函数 变长参数的函数即参数个数可变.参数类型不定 的函数.最常见的例子是printf函数.scanf函数和高级语言的Format函数.在C/C++中,为了通知编译器函数的参数个数和类型可变(即 ...
- C语言中如何使用宏
C(和C++)中的宏(Macro)属于编译器预处理的范畴,属于编译期概念(而非运行期概念).下面对常遇到的宏的使用问题做了简单总结. 宏使用中的常见的基础问题 #符号和##符号的使用 ...符号的 ...
- Qt中的Q_D宏和d指针
_ZTS7QObject 一.Q_D的在文件中的提法 Q_D的设置意在方便地获取私有类指针,文件为qglobal.h.下面的##是宏定义的连字符.假设类名是A,那么A##Private翻译过来就是AP ...
- opencv中矩阵计算的一些函数
转自:http://blog.sina.com.cn/s/blog_7908e1290101i97z.html 综述: OpenCV有针对矩阵操作的C语言函数. 许多其他方法提供了更加方便的C++接口 ...
随机推荐
- Generator function vs Async/Await
Generator function vs Async/Await generator async /await refs xgqfrms 2012-2020 www.cnblogs.com 发布文章 ...
- js spider
js spider https://gist.github.com/xgqfrms-GitHub/0bf82ff06037a0d1776c9f30033cbfd1 https://www.cnblog ...
- virtual scroll list / dynamic dom list
virtual scroll list / dynamic dom list 虚拟滚动列表 1亿条数据的处理渲染方法 时间分片,不阻塞 DOM web workers 后台进程 Array buffe ...
- Masterboxan INC发布印尼电商市场报告
据海外媒体报导,Masterboxan INC(编号:20151264097)发布了印尼电商市场观察报告,指出印尼电商市场仍然有很大的发展潜力. Masterboxan INC表示,与发达国家从 PC ...
- Spring学习过程中遇到的No bean named 'beanId' is defined报错
ApplicationContext applicationContext= new ClassPathXmlApplicationContext("bean.xml");Obje ...
- Recycle 只显示一行BUG
学习Recycle 两天了,照着网上的Adapter写了2个Demo,结果测试的时候发现,第一个Demo 显示.点击都正常,第二个Demo的Adapter合第一个一模一样,仅仅是类名不同,结果显示的时 ...
- Python学习笔记_购物车案例
goods_dic = { "iphone":6000, "ipad":3000, "T-shirt":100, "coffee& ...
- 如何用python自动编写《赤壁赋》word文档
目录 前言 安装-python-docx 一.自动编写<赤壁赋> 准备数据 新建文档 添加标题 添加作者 添加朝代 添加图片 添加段落 保存word文档 二.自动提取<赤壁赋> ...
- 字符串拼接出现null的问题
最近在开发的过程中遇到这样的问题,原因是在做一个需求的时候,要求将解密的号码和前缀进行拼接.一开始在这个拼接的过程中,没有考虑到数据校验的问题,因为有可能他的前缀或者其他需要拼接的字段在前端传递的过程 ...
- JavaScript疑难点
什么是闭包 我个人理解闭包就是函数中嵌套函数,但是嵌套的那个函数必须是返回值,才构成闭包: //标准的闭包 function fn(){ var i=1; return function fnn(){ ...