目录
一、宏定义中 “#”知识点
1、直接转换字符串,不展开。
2、转换出的结果一定是“字符串”。
二、宏定义中 ## 知识点
1、应用场景
2、“##”的作用是将 左右两边的参数做整体字符串拼接替换
3、经过 ## 替换后的内容必须 有一个 同名的 变量与之对应。
4、 只拼接,不展开。
5、## 操作 动态函数指针 案例代码
一、宏定义中 “#”知识点
#的作用是将“#”后面的宏参数进行字符串转换操作,也就是将#后面的参数 两边加上一对双引号,使其成为字符串。
这里面有几个知识点:
1、直接转换字符串,不展开。
这句话的意思是,带参数宏定义也是宏,而不是普通函数,所以要保留宏的基本特性,也就是全部替换,而不展开。示例代码:
#include <stdio.h>#include <stdlib.h>#define CONVERT(a) #aint main(int argc, char *argv[]) {int a = 6;printf("res:%s\n", CONVERT(a));return 0;}
运行结果:
res:a
2、转换出的结果一定是“字符串”。
代码如下:
#include <stdio.h>#include <stdlib.h>#define CONVERT(a) #aint main(int argc, char *argv[]) {printf("string print:%s\n", CONVERT(6));// 字符串格式打印printf("int print:%d\n", CONVERT(6));// 整型打印return 0;}
运行结果如下:
string print:6int print:4210688
二、宏定义中 ## 知识点
1、应用场景
## 的 应用场景主要是 函数指针的动态绑定,使用该宏参数,可以实现 同类型函数指针 赋值或者引用的 方便操作。这个后面会有代码详细分析。
2、“##”的作用是将 左右两边的参数做整体字符串拼接替换
不管 ## 左右两边是字母还是数字,最终都是作为 一个整体 拼接成一个字符串。代码如下:
#include <stdio.h>#include <stdlib.h>#define FUNC(a) func_##avoid func_1(void){printf("this is func 1.\n");}void func_2(void){printf("this is func 2.\n");}int main(int argc, char *argv[]) {FUNC(1)();FUNC(2)();return 0;}
3、经过 ## 替换后的内容必须 有一个 同名的 变量与之对应。
比如 运行 FUNC(1),必须要保证 有一个 func_1 函数, 同样的 FUNC(2) 对应 func_2函数,如果没有,编译会报错,提示对象未 定义。
4、 只拼接,不展开。
这个类似于 # ,也是原封不动的转换,并不会进一步展开,比如:
int i = 1;FUNC(i)();
尽管 i = 1,但是 FUNC(i) 的结果是 func_i,而不是 func_1.,所以我们不能够使用 ## 的时候,自作聪明的使用变量。
5、## 操作 动态函数指针 案例代码
在 知识点3中,我们提到 不能使用 变量 和 ## 的结合来实现 动态绑定函数指针,那么我们的程序代码就相对不太方便,尤其是我们 想要定义 一系列的 函数,这些函数主题名相同,但是序号不同,那么这个时候,就推荐使用 结构体 数据结构,代码如下所示:
#include <stdio.h>#include <stdlib.h>#define FUNC(a) func_##avoid func_0(void){printf("this is func 0.\n");}void func_1(void){printf("this is func 1.\n");}void func_2(void){printf("this is func 2.\n");}//包含函数 序号、 函数指针的 结构体typedef struct func_t{int id;void (*func)(void);} func_map_t;// 函数结构体 数组static func_map_t g_func_map[3] = {{0, FUNC(0)},{1, FUNC(1)},{2, FUNC(2)},};int main(int argc, char *argv[]) {g_func_map[0].func(); //间接调用 序号对应的 函数。g_func_map[1].func();g_func_map[2].func();return 0;}
这里需要注意的是,我们在定义 上面的 g_func_map 数组 时,需要 在 函数func_0、func_1、func_2之后,这可能是因为编译器先后顺序的原因,如果g_func_map 在这三个函数之前,那么会出现 编译报错信息,显示 这3个函数未定义,可以简单的认为,在定义的时候,数据类型从 前面 查找, 而不是全局查找。
运行结果如下:
this is func 0.this is func 1.this is func 2.