C语言-#和##的具体用法

描述

C语言中,在宏里面使用’#’和’##’有它非常神奇的作用。在宏定义的替换的过程中,#号可以作为一个预处理运算符,把宏参数转换为字符串。##运算符则可以把两个宏参数组合在一起。下面就来说说具体的用法。

1、一般用法

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

下面的代码是演示代码:

 

#include 

#define STRING(s)           #s
#define CONNECT(a, b)       (int)(a##e##b)

int main(void)
{
    // 输出字符串"abcdefg"
    printf("string:%s
", STRING(abcdefg));

    // 2e3输出:2000
    printf("connect:%d
", CONNECT(2,3));

    return 0;
}

 

运行结果如下图:

代码

2016-03-21_171313

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

需要注意的是:凡是宏定义里有用'#'或'##'的地方,宏参数是不会再展开。

(1)、非’#’和’##’的情况

 

#include 

#define TOW                 (2)
#define MUL(a,b)            (a*b)

int main(void)
{
    printf("%d*%d=%d
", TOW, TOW, MUL(TOW,TOW));

    return 0;
}

 

上面代码中打印那行的宏会被展开为:

 

printf("%d*%d=%d
", (2), (2), ((2)*(2)));

 

(2)、当有'#'或'##'的时候

 

#include 
#include 

#define A               (2)
#define STR(s)          #s
#define CONS(a,b)       (int)(a##e##b)

int main(void)
{
    // INT_MAX 这行会被展开为:printf("int max: %s
", "INT_MAX");
    printf("int max: %s
", STR(INT_MAX));

    // 这一行会被展开为:printf("%s
", (int)(AeA));
    printf("%s
", CONS(A, A));

    return 0;
}

 

上面的代码在编译时会失败,INT_MAX和A都不会再被展开,然而解决这个问题的方法也很简单。加多一层中间转换宏。加这层宏的用意是把所有宏的参数在这层里全部展开,那么在转换宏里的那一个宏(_STR)就能得到正确的宏参数。

 

#include 
#include 

#define A               2
#define _STR(s)         #s
#define STR(s)          _STR(s) // 转换宏
#define _CONS(a,b)      (int)(a##e##b)
#define CONS(a,b)       _CONS(a,b) // 转换宏

int main(void)
{
    // INT_MAX,int型的最大值,为一个变量
    printf("int max: %s
", STR(INT_MAX));

    printf("CONS(A, A):%d
", CONS(A, A));

    return 0;
}

 

其中代码:

 

printf("int max: %s
", STR(INT_MAX));

 

输出为:int max: 2147483647,STR(INT_MAX) ---> _STR(2147483647) 然后再转换成字符串。

第二个输出代码:

 

printf("CONS(A, A):%d
", CONS(A, A));

 

输出为:CONS(A, A):200,CONS(A, A) ---> _CONS(2, 2) ---> int(2e2) 。

3、'#'和'##'的一些应用特例

(1)、合并匿名变量名

 

#include 

#define ___ANONYMOUS1(type,var,line)    type   var##line
#define __ANONYMOUS0(type, line)        ___ANONYMOUS1(type, _anonymous, line)
#define ANONYMOUS(type)                 __ANONYMOUS0(type, __LINE__)

int main(void)
{
    ANONYMOUS(static int);

    _anonymous9 = 666;

    printf("_anonymous9:%d
", _anonymous9);

    return 0;
}

 

上述代码:ANONYMOUS(static int);最终展开为:static int _anonymous9; // 9表示该行行号;,下面分析下具体的展开过程:

第一次展开:ANONYMOUS(static int);   --->   __ANONYMOUS0(static int, __LINE__);;

第二次展开:__ANONYMOUS0(static int, __LINE__);   --->   ___ANONYMOUS1(static int, _anonymous, 9);;

第三次展开:___ANONYMOUS1(static int, _anonymous, 9);    --->   static int   _anonymous9;;

对于宏的展开过程,每次只能解开当前层的宏,所以__LINE__在第二层才能被解开。

(2)、获取文件名

 

#include 

#define _GET_FILENAME(filename)         #filename
#define GET_FILENAME(filename)          _GET_FILENAME(filename)

int main(void)
{
    char filename[] = GET_FILENAME(__FILE__);

    printf("filename:%s
", filename);

    return 0;
}

 

当然了,上述的宏也可以获取__DATE__,__LINE__等宏实际对应的值,上面专门定义了一个数组来存储转换后的值,实际使用时是否定义数组可自行安排。

  审核编辑:汤梓红

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分