C语言中#和##的作用
- 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
hello 122 333444
##符号称为连接符,将两个或多个标记连接为一个合法的标识符;代码如下:
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
var2 : 2
比如要做一个菜单项由变量和函数指针组成的结构体数组,并且希望在函数名和菜单项命名之间有直观的名字上的关系,那么下面的代码就非常实用:可能在有些规则编码中是不允许使用的,因为这样,没有明确的关系,难以查找。这里只是总结一下
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
2quit_command name: quit
help_command name: helpCOMMAND宏在这里充当一个代码生成器的作用,这样可以在一定程度上减少代码密度,间接地也可以减少不留心造成地错误,
我们还可以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
t9=9
注意在这个例子中,
上面的是一般用法
- 当宏参数是另一个宏的时候,需要注意的是凡宏定义里有用
#
和##的地方,宏参数是不会再展开 非
#和
##`的情况:
1 | #define TOW (2) |
- 当有
#
和##
的时候INTPTR_MAX和A都不会展开然而解决这个问题方法很多,加一层中间转换宏,加这层宏的用意是把所有宏的参数在这层里全部展开,那么在转换宏里的那一个宏就能得到正确的宏参数。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");输出结果: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 ERROR1
2int 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
2quit_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);