C/C++中“#”和“##”的作用和用法

来源:互联网 发布:stc15f2k60s2单片机 编辑:程序博客网 时间:2024/06/11 14:55
在C/C++的宏中,”#”的功能是将其后面的宏参数进行字符串化操作(Stringfication),简单说就是在对它所引用的宏变量通过替换后在其左右各加上一个双引号。

而”##”被称为连接符(concatenator),用来将两个子串Token连接为一个Token。注意这里连接的对象是Token就行,而不一定是宏的变量。还可以n个##符号连接n+1个Token,这个特性是#符号所不具备的。

凡是宏定义里有用’#’或’##’的地方宏参数是不会再展开。

若要使’#’和’##’的宏参数被展开,可以加多一层中间转换宏。加这层宏的用意是把所有宏的参数在这层里全部展开,那么在转换宏里的那一个宏就能得到正确的宏参数。

#include <iostream>using namespace std;//test1#define WARN_IF(EXP) if (EXP) fprintf(stderr, "warning: "#EXP);//test2#define STR(s) #s//test3#define _STRI(s) #s#define STRI(s) _STRI(s) //转换宏//test4#define paster(n) printf("token"#n" = %d", token##n)//test5#define _CONS(a, b) int(a##+##b)#define CONS(a, b) _CONS(a, b) //转换宏//test6#define  _GET_FILE_NAME(f)   #f#define  GET_FILE_NAME(f)    _GET_FILE_NAME(f)  //转换宏//test7#define  _TYPE_BUF_SIZE(type)  sizeof #type#define  TYPE_BUF_SIZE(type)   _TYPE_BUF_SIZE(type)//test8#define D(x)  #@x  //仅对单一标记转换有效void main(int argc, char* argv[]){    //test1    int divider = 0;    WARN_IF(divider == 0);//warning: divider == 0    printf("\n");    //test2    printf("int max: %s\n", STR(INT_MAX));//int max: INT_MAX    //test3    printf("int max: %s\n", STRI(INT_MAX));//int max: 2147483647    //test4    int token9 = 9;    paster(9);//token9 = 9    printf("\n");    //test5    int A = 15, B = 2;    printf("A + B = %d\n", CONS(A, B));//A + B = 17    //test6    char  file_name[] = GET_FILE_NAME(__FILE__);    cout<<file_name<<endl;}

#define P(EX) cout<<#EX<<":"<<EX<<endl;int main(){    int a[10];    for (int i = 0; i < 10; i++)        a[i] = i;    int *ip = a;    P(*ip);    P(*++ip);    P(*(ip+5));    int *ip2 = ip + 5;    P(*ip2);    P(*(ip2 - 4));    P(*--ip2);    P(ip2-ip);         //指针相减,注意:指针之间不能相加    return 0;}

宏中"#"和"##"的用法
一、一般用法
我们使用#把宏参数变为一个字符串,用##把两个宏参数贴合在一起.
用法:
#include <stdio.h>#include <limits.h>using namespace std;//”#”的功能是将其后面的宏参数进行字符串化操作(Stringfication),简单说就是在对它所引用的宏变量通过替换后在其左右各加上一个双引号。#define STR(s)     #s//而”##”被称为连接符(concatenator),用来将两个子串Token连接为一个Token#define CONS(a,b)  int(a##e##b)int main(){    printf(STR(vck));           // 输出字符串"vck"    printf("\n");    printf("%d\n", CONS(2,3));  // 2e3 输出:2000    return 0;}



二、当宏参数是另一个宏的时候
需要注意的是凡宏定义里有用'#'或'##'的地方宏参数是不会再展开.
1, 非'#'和'##'的情况
#include <stdio.h>#include <limits.h>#define TOW      (2)#define MUL(a,b) (a*b)int main(){    printf("%d*%d=%d\n", TOW, TOW, MUL(TOW,TOW)); //这行的宏会被展开为:printf("%d*%d=%d\n", (2), (2), ((2)*(2)));    return 0;};

2, 当有'#'或'##'的时候
#include <stdio.h>#include <limits.h>#define A          (2)#define STR(s)     #s#define CONS(a,b)  int(a##e##b)int main(){    printf("int max: %s\n",  STR(INT_MAX));    // 这行会被展开为:printf("int max: %s\n", "INT_MAX");    //printf("%s\n", CONS(A, A));               // compile error 这一行则是:printf("%s\n", int(AeA));    //INT_MAX和A都不会再被展开, 然而解决这个问题的方法很简单. 加多一层中间转换宏.    //加这层宏的用意是把所有宏的参数在这层里全部展开, 那么在转换宏里的那一个宏(_STR)就能得到正确的宏参数.    return 0;}#include <stdio.h>#include <limits.h>#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(){    printf("int max: %s\n", STR(INT_MAX));  //输出为: int max: 0x7fffffff  转换过程:  STR(INT_MAX) -->  _STR(0x7fffffff) 然后再转换成字符串;   // printf("%d\n", CONS(A, A)); //输出为:200   转换过程:CONS(A, A)  -->  _CONS((2), (2))  --> int((2)e(2))    return 0;}
三、'#'和'##'的一些应用特例
1、合并匿名变量名
#define  ___ANONYMOUS1(type, var, line)  type  var##line
#define  __ANONYMOUS0(type, line)  ___ANONYMOUS1(type, _anonymous, line)
#define  ANONYMOUS(type)  __ANONYMOUS0(type, __LINE__)
例:ANONYMOUS(static int);  即: static int _anonymous70;  70表示该行行号;
第一层:ANONYMOUS(static int);  -->  __ANONYMOUS0(static int, __LINE__);
第二层:                        -->  ___ANONYMOUS1(static int, _anonymous, 70);
第三层:                        -->  static int  _anonymous70;
即每次只能解开当前层的宏,所以__LINE__在第二层才能被解开;

2、填充结构
#define  FILL(a)   {a, #a}
enum IDD{OPEN, CLOSE};
typedef struct MSG{
  IDD id;
  const char * msg;
}MSG;
MSG _msg[] = {FILL(OPEN), FILL(CLOSE)};
相当于:
MSG _msg[] = {{OPEN, "OPEN"},
              {CLOSE, "CLOSE"}};

3、记录文件名
#define  _GET_FILE_NAME(f)   #f
#define  GET_FILE_NAME(f)    _GET_FILE_NAME(f)
static char  FILE_NAME[] = GET_FILE_NAME(__FILE__);

4、得到一个数值类型所对应的字符串缓冲大小
#define  _TYPE_BUF_SIZE(type)  sizeof #type
#define  TYPE_BUF_SIZE(type)   _TYPE_BUF_SIZE(type)
char  buf[TYPE_BUF_SIZE(INT_MAX)];
     -->  char  buf[_TYPE_BUF_SIZE(0x7fffffff)];
     -->  char  buf[sizeof "0x7fffffff"];
这里相当于:
char  buf[11];

0 0
原创粉丝点击