- C语言中#和##的作用
- 提供代码都是可以正常运行起来
#和##符号是C和C++的宏(macro)属于编译器预处理的范畴,编译期间完成
- #的功能是将其后面的宏参数进行字符串化操作;#符号是把传递过来的参数多做字符串进行处理;简单说就是在对它所引用宏参数在其左右加一个双引号,示例代码如下:
1 2 3 4 5 6 7 8 9
| #include <stdio.h>
#define str(param) #param //#将param参数经行字符串化
int main() { printf(str(hello 122 333444\n)); return 0; }
|
输出结果:
- ##符号称为连接符,将两个或多个标记连接为一个合法的标识符;代码如下:
1 2 3 4 5 6 7 8 9 10 11 12
| #include <stdio.h> /* ## */ #define var(x) var##x int main() { int var(1) = 1; int var(2) = 2; int var(3) = 3;
printf("var2 : %d\n", var2); return 0; }
|
运行结果:
- 比如要做一个菜单项由变量和函数指针组成的结构体数组,并且希望在函数名和菜单项命名之间有直观的名字上的关系,那么下面的代码就非常实用:可能在有些规则编码中是不允许使用的,因为这样,没有明确的关系,难以查找。这里只是总结一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| #include <stdio.h>
#define barrier(x) barrier##x #define COMMAND(NAME) {NAME , NAME##_command}
/**/ struct command { char *name; void(*function)(void); };
/** * @brief 建议在两个需要都被打印的数组中添加一个变量,比如下面所示; * 或者可以指定printf打印字符串长度,至于原因,自己想想 */ char quit[4] = {"quit"}; char barrier(0) = 0; /*阻隔*/ char help[4] = {"help"}; void quit_command(void); void help_command(void);
/*在这里已经对变量赋值和函数指针赋值,展开效果: * struct command commands[] = {{quit quit_command},{help help_command}}; */ struct command commands[] = { COMMAND(quit) ,COMMAND(help)};
void quit_command(void) { printf("quit_command name: %-4.4s\n", commands[0].name); /*-4.4s:关于这个可以在本博客中搜索 "printf打印指定长度字符串" */ }
void help_command(void) { printf("help_command name: %s\n", commands[1].name); }
int main() { commands[0].function(); commands[1].function(); return 0; }
|
运行结果:
1 2
| quit_command name: quit help_command name: help
|
COMMAND宏在这里充当一个代码生成器的作用,这样可以在一定程度上减少代码密度,间接地也可以减少不留心造成地错误,
- 我们还可以n个##连接n+1个字符串,这个也是#符号不具备地,比如:
1 2 3 4 5 6
| #define LINK_MULT(a,b,c,d) a##_##b##_##c##_##d typedef struct _record_type LINK_MULT(name,Company,Position,salay); /* * 语句展开效果: * typedef struct _record_type typedef struct _record_type */
|
- ##功能是在带参的宏定义中,将两个字符串连接起来,形成一个新的子串;
假设程序中已经定义这样一个带参的宏
1 2 3 4 5 6 7 8 9
| #define poster(n) printf("t"#n"=%d\n",t##n); /*同时又定义了一个整形变量*/ int t9 = 9; int main() { /*在编译时,poster(9)扩展为 printf("t""9""=%d\n",t9);*/ poster(9); return 0; }
|
运行结果:
注意在这个例子中,
上面的是一般用法
- 当宏参数是另一个宏的时候,需要注意的是凡宏定义里有用
#和##的地方,宏参数是不会再展开 非#和##`的情况:
1 2 3 4 5
| #define TOW (2) #define MUL(a,b) (a*b) printf("%d * %d = %d\n",TOW,TOW,MUL(TOW,TOW)); 这行的宏展开为: printf("%d * %d = %d\n",2,2,MUL(2,2));
|
- 当有
#和##的时候
1 2 3 4 5 6 7
| #define A 2 #define STR(s) #s #define CONS(a,b) (int)(a##e##b) printf("int max:%s\n", STR(INTPTR_MAX)); //INTPTR_MAX =》stdint.h //展开 printf("int max:%s\n", "INTPTR_MAX"); //INTPTR_MAX =》stdint.h printf("%s\n",CONS(A,A)); //COMPILE ERROR //展开 printf("%s\n","AeA");
|
INTPTR_MAX和A都不会展开然而解决这个问题方法很多,加一层中间转换宏,加这层宏的用意是把所有宏的参数在这层里全部展开,那么在转换宏里的那一个宏就能得到正确的宏参数。
1 2 3 4 5 6 7 8
| #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) //转换宏
printf("int max:%s\n", STR(INTPTR_MAX)); //INTPTR_MAX =》stdint.h printf("CONS: %d\n",CONS(A,A)); //COMPILE ERROR
|
输出结果:
1 2
| int max:2147483647i32 CONS: 200
|
#和##的一些应用,合并匿名创建变量名
1 2 3 4 5
| #define _ANONYMOUS1(type,var ,line) type var##line #define _ANONYMOUS0(type,line) _ANONYMOUS1(type,anonymous ,line) #define ANONYMOUS0(type) _ANONYMOUS0(type,__LINE__)
ANONYMOUS0(static int) = 100;
|
- 填充结构体
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| #include <stdio.h>
#define barrier(x) barrier##x #define COMMAND(NAME) {NAME , NAME##_command}
/**/ struct command { char *name; void(*function)(void); };
/** * @brief 建议在两个需要都被打印的数组中添加一个变量,比如下面所示; * 或者可以指定printf打印字符串长度,至于原因,自己想想 */ char quit[4] = {"quit"}; char barrier(0) = 0; /*阻隔*/ char help[4] = {"help"}; void quit_command(void); void help_command(void);
/*在这里已经对变量赋值和函数指针赋值,展开效果: * struct command commands[] = {{quit quit_command},{help help_command}}; */ struct command commands[] = { COMMAND(quit) ,COMMAND(help)};
void quit_command(void) { printf("quit_command name: %-4.4s\n", commands[0].name); /*-4.4s:关于这个可以在本博客中搜索 "printf打印指定长度字符串" */ }
void help_command(void) { printf("help_command name: %s\n", commands[1].name); }
int main() { commands[0].function(); commands[1].function(); return 0; }
|
运行结果:
1 2
| quit_command name: quit help_command name: help
|
- 记录文件名
1 2 3 4
| #define _GET_FILE_NAME(f) #f #define GET_FILE_NAME(f) _GET_FILE_NAME(f) char file_name[] = { GET_FILE_NAME(__FILE__)}; printf("file_name %s\n", file_name);
|
- 得到一个数值类型所对应的字符串缓冲大小
1 2 3 4
| #define _TYPE_BUF_SIZE(type) sizeof(#type) #define TYPE_BUF_SIZE(type) _TYPE_BUF_SIZE(type) char buf[TYPE_BUF_SIZE(INT32_MAX)] = { GET_FILE_NAME (INT32_MAX) }; printf("buf %s\n", buf);
|