本文整理自csdn。

#define f(a,b) a##b
#define d(a) #a
#define s(a) d(a)

void main( void )
{
    puts(d(f(a,b)));
    puts(s(f(a,b)));
}

输出结果:
f(a,b)
ab

分析:  ##把两个符号连起来
    #a指把a当成符号,就是把#后面的看成字符串

# 和 ## 操作符是和#define宏使用的. 使用# 使在#后的首个参数返回为一个带引号的字符串. 例如, 命令 
    #define to_string( s ) # s
将会使编译器把以下命令 
    cout < < to_string( Hello World! ) < < endl;
理解为 
    cout < < "Hello World!" < < endl;
使用##连结##前后的内容. 例如, 命令 
    #define concatenate( x, y ) x ## y
    ...
    int xy = 10;
    ...
将会使编译器把 
    cout < < concatenate( x, y ) < < endl;
解释为 
    cout < < xy < < endl;
理所当然,将会在标准输出处显示'10'.

puts(d(f(a,b)));  ----> 因为d宏中的参数是另外一个宏,且带##,所以作为参数的宏不展开,相当于
                            puts(#f(a,b));----->puts("f(a,b)");
puts(s(f(a,b))); ----> 因为s宏中的参数是另外一个宏,但不带##,所以作为参数的宏先展开,相当于
                            puts(s(ab));----->puts(d(ab));---->puts(#ab);---->puts("ab");

#define f(a,b) a##b
#define d(a) #a --》 以"#"开头的,直接替换,不展开:immediately replaced by the unexpanded actual argument
#define s(a) d(a) --》 非以"#"开头的,先展开,再替换,也就是一般的情况

所以就两种情况:
1,不以"#"开头的,先展开参数a,然后是替换代码:puts(s(f(a,b)));-->puts(s(ab))-->puts(d(ab))-->puts("ab")
2,以"#"开头的,直接替换,不展开:puts(d(f(a,b)))-->puts("f(a,b)")

#include <stdio.h>
#define DIRECT_LITERAL(a)  #a
#define INDIRECT_LITERAL(a) DIRECT_LITERAL(a)

int main(void)
{
    puts(DIRECT_LITERAL(INDIRECT_LITERAL(a + b)));
    puts(INDIRECT_LITERAL(DIRECT_LITERAL(a + b)));
    return 0;
}
这其实从编译角度的展开归约也可以理解啊。

以上代码第一种情况,当预编译器看到DIRECT_LITERAL后查到它是宏定义,定义为#a,此时后面的参数部分就会以#a的形式生成到源文件中。也就是说,预编译后的源文件中,替代第一条语句的就是:
puts("INDIRECT_LITERAL(a + b)");输出则是INDIRECT_LITERAL(a + b)

而对于第二条语句,当预编译器看到INDIRECT_LITERAL后查到它是宏定义,定义为DIRECT_LITERAL(a),这时先把它作为DIRECT_LITERAL(DIRECT_LITERAL(a + b))的形式暂存起来,你也可以理解为这个状态是语法树的当中一个叶结点。然后再分析后面的DIRECT_LITERAL后面的参数部分,即:DIRECT_LITERAL(a + b),同样,预编译器会将它归约为"a + b"的形式。这样对于里面的DIRECT_LITERAL(a + b)的形式就完全确定下来了,那么这个值就可以充当叶子结点,即它底下不会再有结点。然后再回到刚才那个状态,DIRECT_LITERAL("a + b")最后就是"\"a + b\""。所以这里输出是"a + b"。

值得注意的是#a是将参数a转为字符串形式。所以像DIRECT_LITERAL(a)的展开形式是字符串常量"a"
那么DIRECT_LITERAL("a")展开就是"\"a\""。

#include <stdio.h>
#define DIRECT_LITERAL(a)  #a
#define INDIRECT_LITERAL(a) DIRECT_LITERAL(a)

#define DIRECT_CAT(a, b)   a##b
#define INDIRECT_CAT(a, b)  DIRECT_CAT(a, b)

int main(void)
{
    puts(DIRECT_LITERAL(INDIRECT_LITERAL(a + b)));
    puts(INDIRECT_LITERAL(DIRECT_LITERAL(a + b)));
    puts(INDIRECT_LITERAL(DIRECT_CAT(INDIRECT_CAT(a, b), INDIRECT_CAT(c, d))));
    puts(INDIRECT_LITERAL(INDIRECT_CAT(DIRECT_CAT(a, b), DIRECT_CAT(c, d))));
    return 0;
}

#define中 #与##的神奇用法相关推荐

  1. C语言中#define中的一些特殊用法

    转载自:http://blog.sina.com.cn/s/blog_4a4365030100edq7.html define是C语言中的预处理命令,它用于宏定义,可以提高源代码的可读性,为编程提供方 ...

  2. #define宏定义中的#,##,@#,\ 这些符号的神奇用法

    C/C++ 宏命令的神奇用法. 先看下面三条语句: #define Conn(x,y) x##y #define ToChar(x) #@x #define ToString(x) #x 1 2 3 ...

  3. excel三次样条函数_Excel中F1到F12键的神奇用法

    Excel中F1到F12键的神奇用法,可惜很多人都不知道... F1 帮助快捷键 在使用Excel遇到问题时,最简单粗暴的方法就是按F1,会出现帮助的窗口,然后输入查询内容即可. F2 编辑单元格 F ...

  4. python中rect用法_【opencv基础】Rect类的神奇用法

    前言 最近看github上源码发现对两个cv::Rect使用相与(&)操作,猛地感觉自己蒙啦,Rect类还有这种神奇用法?!翻看opencv官网Rect类,果然如此! opencv中Rect类 ...

  5. C++语言中std::array的神奇用法总结,你需要知道!

    摘要:在这篇文章里,将从各个角度介绍下std::array的用法,希望能带来一些启发. td::array是在C++11标准中增加的STL容器,它的设计目的是提供与原生数组类似的功能与性能.也正因此, ...

  6. wince中的hook(钩子)用法

    wince中的hook(钩子)用法 Hook(钩子)是一种在消息到达目标窗口前进行截获的技术.使用钩子主要使用以下三个函数SetWindowsHookEx:创建钩子 CallNextHookEx:将消 ...

  7. C++中WSAAsyncSelect模型的用法例程

     本文实例讲述了C++中WSAAsyncSelect模型的用法.分享给大家供大家参考.具体实现方法如下: TCPServer.cpp源文件如下: 复制代码 代码如下: #include " ...

  8. java sendmessage函数_vc中SendMessage自定义消息函数用法实例

    本文实例讲述了vc中SendMessage自定义消息函数用法,分享给大家供大家参考.具体如下: SendMessage的基本结构如下: SendMessage( HWND hWnd,  //消息传递的 ...

  9. #define中的三个特殊符号:#,##,#@

    #define中的三个特殊符号:#,##,#@ (关于#define的用法,看这里 http://www.cppblog.com/kenny/archive/2011/04/26/145087.htm ...

最新文章

  1. [kuangbin带你飞]专题五查并集
  2. LaTeX:公式及编号
  3. Android的消息处理机制——Looper,Handler和Message浅析
  4. OpenCV cv :: UMat与DirectX11曲面的互操作性的实例(附完整代码)
  5. MATLAB代写要求应该怎么写,matlab/simulink程序代写
  6. 协同过滤算法评测python_元学习和推荐系统:协同过滤算法选择问题的文献综述和实证研究...
  7. combox 增加请选择_本命佛怎么请?
  8. oracle安装时EM,EM 安装时报错 - Oracle数据库管理 - ITPUB论坛-中国专业的IT技术社区...
  9. atlas 又多了几个新控件
  10. 2018年入门python,推荐这样几本好书!
  11. 2 什么样的顾客会选择离开
  12. UML用例图分析——铁路售票系统
  13. 项目实战:Qt+ffmpeg摄像头检测工具
  14. 【已解决】你遇到过windows更新之后,输入法突然不好用的情况吗?
  15. Android requires compiler compliance level 5.0 or 6.0. Found '1.7' instead.
  16. 黑作坊磨皮大师完美破解版
  17. 【python】图片着色后存储为“JPEG”格式存在明显色差的测试
  18. 酒店管理系统/基于ssm的酒店管理系统/基于javaweb的酒店管理系统的设计与实现
  19. redis集群数据迁移方式、宕机
  20. MATLAB处理数据,掌握这几个小技巧就够了

热门文章

  1. python中以下关于列表描述错误的_在Python中,以下关于函数的描述错误的是哪一项?...
  2. 科研|我最煎熬的学术时刻,是耗时3年完成了一篇论文
  3. 只要沾上婚恋焦虑,她们就王者变青铜
  4. 推荐系统入门必读论文
  5. 在scrapy中parse函数里面xpath的内容打印不出来_scrapy 爬虫爬取的数据json模式存储...
  6. MySQL 字符集支持
  7. 每周到岗上班3天,2天可在家办公!携程3+2工作模式来了
  8. 顺丰同城通过港交所聆讯 今年前五个月收入为30.46亿元
  9. 南瓜电影将和腾讯合作 获海量视频版权授权
  10. 华为车规芯片麒麟990A架构曝光