• 宏参数(Arguments)的扩展


    宏分为两种,一种是 object-like 宏,比如:

    #define STR "Hello, World!"

    另一种是 function-like 宏,比如:

    #define MIN(X, Y) ((X) < (Y) ? (X) : (Y))

    对于 function-like 宏,定义时的参数叫 Parameters,比如上面宏 MIN 的参数 X、Y,当调用时,传递的参数叫 Arguments。

    宏参数 Arguments

    当给宏传递参数 Arguments 时,可以不用全部传递,比如:

    MIN(a, b)  ->  ((a) < (b) ? (a) : (b)) // 完全传递
    
    MIN(, b) -> (() < (b) ? () : (b)) // 只传递后一个
    
    MIN(a, ) -> ((a) < () ? (a) : ()) // 只传递前一个
    
    MIN(,) -> (() < () ? () :()) // 这种允许
    
    MIN(, ,) // 报错,接收2个参数,传递了3个
    
    MIN() // 报错,接收2个参数,传递了1个

    宏参数 Arguments 的扩展

    当向宏中传递参数 Arguments 时,在参数替换到宏里面之前,首先要对参数 Arguments 进行完全的扩展,当参数扩展完毕之后,才将最终扩展的结果替换到宏里面,同时再对整个宏进行扩展。比如调用宏 MIN(MIN(a, b), c),那么首先第一个参数 MIN(a, b)要进行扩展,扩展的结果为 ((a) < (b) ? (a) : (b)),由于第2个参数 c 不用扩展,也就是第1步得到的扩展结果为:

    MIN(((a) < (b) ? (a) : (b)), c)

    接下来进行第2步扩展,得到的结果为:

    ((((a) < (b) ? (a) : (b))) < (c) ? (((a) < (b) ? (a) : (b))) : (c))

    这样做的一个好处是为了防止宏的嵌套调用,比如有下面一个宏定义:

    #define f(x) x

    如果有如下调用 f(f(1)),假设第一步不将参数 f(1) 完全展开,就会出现 f(f(1)) 被展开为 f(1),由于间接的自引用,宏不再继续展开,此时得到的结果就为 f(1)。而有了2步扩展,第一步参数 f(1) 被扩展成 1,然后替换后继续扩展,可以得到结果就是1。

    自引用宏

    一个宏在定义时,如果宏名出现在了宏定义中,那么就是一个自引用宏,比如:

    #define foo (4 + foo)

    如果调用这个宏 foo,按照上面两步展开的过程,那么将会是一个无限循环的过程。首先 foo 展开为 (4 + foo),然后 (4 + foo) 中的 foo 继续展开成 (4 + foo) 成为 (4 + (4 + foo)),如此继续下去。但是实际上,对于自引用宏,只扩展1次,后面不会再做扩展,也就是说调用宏 foo,最终的扩展结果就是 (4 + foo)。

    对于自引用宏的一种特殊情况就是间接自引用,比如有如下宏定义:

    #define x (4 + y)
    #define y (2 * x)

    当调用宏 x 时,首先扩展为 (4 + y),然后对 y 进行扩展,结果为 (4 + (2 * x)),如果此时继续对 x 进行扩展,那么就会无限递归,为了处理这种情况,扩展会在这一步终止,也就是最终结果是 (4 + (2 * x))。

    当调用宏 y 时一样,首先扩展为 (2 * x),然后对 x 进行扩展,结果为 (2 * (4 + y)),扩展到这一步也会停止。

    参数 Arguments 有字符串化(#)和连接(##)操作

    在宏扩展过程当中,当参数 Arguments 有字符串化(#)和连接操作(##)时,参数的扩展就没有第1步。比如有下面宏定义:

    #define AFTERX(x) X_ ## x
    #define XAFTERX(x) AFTERX(x)
    #define TABLESIZE 1024
    #define BUFSIZE TABLESIZE

    当调用 AFTERX(BUFSIZE) 时,由于参数 BUFSIZE 有连接操作(##),那么它就不会继续扩展成 TABLESIZE,TABLESIZE 继续扩展成1024,而是直接使用,也就是最终的扩展结果是 X_BUFSIZE,而不是 X_10。如果想要得到 X_10 的结果,需要做1次间接宏调用,重新定一个宏 XAFTERX 来调用宏 AFTERX,当调用宏 XAFTERX(BUFSIZE) 时,就会得到结果 X_10。

  • 相关阅读:
    【Java每日一题】20170111
    【Java每日一题】20170110
    【Java每日一题】20170109
    【Java每日一题】20170106
    【Java每日一题】20170105
    【Java每日一题】20170104
    【Java每日一题】20170103
    【Java每日一题】20161230
    【Java每日一题】20161229
    【Java每日一题】20161228
  • 原文地址:https://www.cnblogs.com/chaoguo1234/p/16026867.html
Copyright © 2020-2023  润新知