浅析C++中的间接宏函数

 更新时间:2021年04月02日 08:35:20   作者:老胡写代码  
这篇文章主要介绍了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语言结构体定义的方法汇总

    C语言结构体定义的方法汇总

    结构体是一种工具,用这个工具可以定义自己的数据类型。下面通过本文给大家分享了C语言结构体定义的方法汇总,需要的朋友参考下吧
    2017-12-12
  • C++二叉树结构的建立与基本操作

    C++二叉树结构的建立与基本操作

    二叉树是数据结构中的树的一种特殊情况,有关二叉树的相关概念,这里不再赘述,如果不了解二叉树相关概念,建议先学习数据结构中的二叉树的知识点
    2013-10-10
  • C语言中用于修改文件的存取时间的函数使用

    C语言中用于修改文件的存取时间的函数使用

    这篇文章主要介绍了C语言中用于修改文件的存取时间的函数使用,分别为utime()函数和utimes()函数的使用,需要的朋友可以参考下
    2015-09-09
  • 解析C++编程中的继承方面的运用

    解析C++编程中的继承方面的运用

    这篇文章主要介绍了解析C++编程中的继承方面的运用,是C++入门学习中的基础知识,需要的朋友可以参考下
    2015-09-09
  • 详解Bucket Sort桶排序算法及C++代码实现示例

    详解Bucket Sort桶排序算法及C++代码实现示例

    桶排序是一种线性排序算法,这里我们来详解Bucket Sort桶排序算法及C++代码实现示例,需要的朋友可以参考下
    2016-07-07
  • 一文详解C++中隐含的this指针

    一文详解C++中隐含的this指针

    这篇文章主要带大家详细了解一下C++中隐含的this指针,文中通过代码示例和图文介绍的非常详细,对大家的学习或工作有一定的帮助,需要的朋友可以参考下
    2024-01-01
  • 深入浅析 C++ 调用 Python 模块

    深入浅析 C++ 调用 Python 模块

    Python 提供了 C++ 库,使得开发者能很方便地从 C++ 程序中调用 Python 模块。接下来通过本文给大家介绍 C++ 调用 Python 模块的相关知识,需要的朋友参考下吧
    2016-03-03
  • C++ atoi()函数用法案例详解

    C++ atoi()函数用法案例详解

    这篇文章主要介绍了C++ atoi()函数用法案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-09-09
  • C++ EnterCriticalSection简单使用

    C++ EnterCriticalSection简单使用

    线程锁在多线程中可以控制线程的执行顺序,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-08-08
  • c++ 递归锁的使用示例代码

    c++ 递归锁的使用示例代码

    这篇文章主要介绍了c++ 递归锁的使用示例代码,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-08-08

最新评论