zoukankan      html  css  js  c++  java
  • #define中 #与##的神奇用法

    本文整理自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;

  • 相关阅读:
    Flutter 中那么多组件,难道要都学一遍?
    【Flutter实战】自定义滚动条
    Python 为什么只需一条语句“a,b=b,a”,就能直接交换两个变量?
    一篇文章掌握 Python 内置 zip() 的全部内容
    Python 3.10 的首个 PEP 诞生,内置类型 zip() 迎来新特性
    Python 3.10 版本采纳了首个 PEP,中文翻译即将推出
    Python 为什么不支持 i++ 自增语法,不提供 ++ 操作符?
    Python 为什么推荐蛇形命名法?
    Python 为什么没有 main 函数?为什么我不推荐写 main 函数?
    Python 为什么不用分号作终止符?
  • 原文地址:https://www.cnblogs.com/songfeixiang/p/3733668.html
Copyright © 2011-2022 走看看