zoukankan      html  css  js  c++  java
  • #和##在宏定义中使用问题

    1. 一般用法:

    使用#把宏参数变成一个字符串,用##把两个宏参数贴合在一起。

    2. 当宏参数是另一个宏的时候

    需要注意的是凡宏定义里有‘#’或‘##’的地方宏参数是不会展开的。

    转自:http://www.linuxidc.com/Linux/2014-06/102925.htm

    有一道经典的C语言问题,关于宏定义中#和##符号的使用和宏定义展开问题
     
    程序如下:

    #include <stdio.h>
    #define f(a,b) a##b
    #define g(a)  #a
    #define h(a) g(a)
     
    int main()
    {
            printf("%s ", h(f(1,2)));
            printf("%s ", g(f(1,2)));
            return 0;
    }

    答案:第一行:12  第二行:f(1,2)

    说明:

    1、关于符号#和##

    两个符号都只能用于预处理宏扩展。不能在普通的源码中使用它们,只能在宏定义中使用。

    简单的说,#是把宏参数变为一个字符串,##是把两个宏参数连接在一起。

    关于这两个符号的具体意义和用法可以参见两篇文章:

    #和##在宏替换中的作用 http://www.linuxidc.com/Linux/2014-06/102921.htm

    C/C++ 宏中"#"和"##"的用法 http://www.linuxidc.com/Linux/2014-06/102924.htm

    还有GCC帮助文档上的解释:

    3.4 Stringification

    3.5 Concatenation

    2、关于宏展开

    预处理过程的几个步骤:

    1)字符集转换(如三联字符)

    2)断行链接/

    3)注释处理,/* comment */,被替换成空格

    4)执行预处理命令,如#inlcude、#define、#pragma、#error等

    5)转义字符替换

    6)相邻字符串拼接

    7)将预处理记号替换为词法记号

    第4)步即如何展开宏函数的规则:在展开当前宏函数时,如果宏定义中有#或##则不进行宏参数的展开,否则先展开宏参数,再展开当前宏。

    宏替换顺序英文描述如下:

    A parameter in the replacement list, unless preceded by a # or ## preprocessing token or followed by a ## preprocessing token, is replaced by the corresponding argument after all macros contained therein have been expanded.

    3、总结

    综合以上,对于这道题来说,第一行h(f(1,2)),由于h(a)非#或者##所以先展开其参数f(1,2),即12,所以变成h(12),然后再宏替换为g(12),再次替换为12。

    第二行g(f(1,2)),宏g(a)带有#,所以里面的f(1,2)不展开,所以变成f(1,2)

    类似的这种问题在《你必须知道的495个C语言问题》中出现过,在121页的“预处理功能”的问题11.19,有兴趣的朋友可以看一看。

    C++ Primer Plus 第6版 中文版 清晰有书签PDF+源代码 http://www.linuxidc.com/Linux/2014-05/101227.htm

    读C++ Primer 之构造函数陷阱 http://www.linuxidc.com/Linux/2011-08/40176.htm

    读C++ Primer 之智能指针 http://www.linuxidc.com/Linux/2011-08/40177.htm

    读C++ Primer 之句柄类 http://www.linuxidc.com/Linux/2011-08/40175.htm

    C++11 获取系统时间库函数 time since epoch http://www.linuxidc.com/Linux/2014-03/97446.htm

    C++11中正则表达式测试 http://www.linuxidc.com/Linux/2012-08/69086.htm

    本文永久更新链接地址http://www.linuxidc.com/Linux/2014-06/102925.htm

  • 相关阅读:
    N46期第一周作业
    马哥博客作业第五周
    马哥博客作业第四周
    马哥博客作业第三周
    04go条件和循环
    03go运算符
    01go变量和常量
    02vue指令-1
    01vue初识
    05django模板层
  • 原文地址:https://www.cnblogs.com/embedded-linux/p/4774198.html
Copyright © 2011-2022 走看看