现在的位置: 首页 > 自动控制 > 工业·编程 > 正文

C语言 带参数宏定义中 # 和 ## 知识点总结、代码分析

2019-01-07 21:40 工业·编程 ⁄ 共 1888字 ⁄ 字号 暂无评论

一、宏定义中 “#”知识点

  #的作用是将“#”后面的宏参数进行字符串转换操作,也就是将#后面的参数 两边加上一对双引号,使其成为字符串

这里面有几个知识点:

1、直接转换字符串,不展开。

这句话的意思是,带参数宏定义也是宏,而不是普通函数,所以要保留宏的基本特性,也就是全部替换,而不展开。示例代码:

#include <stdio.h>

#include <stdlib.h>

#define CONVERT(a) #a

int 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) #a

int main(int argc, char *argv[]) {

printf("string print:%s\n", CONVERT(6));     // 字符串格式打印

printf("int print:%d\n", CONVERT(6));     // 整型打印

return 0;

}

运行结果如下:

string print:6

int print:4210688

二、宏定义中 ## 知识点

1、应用场景

     ## 的 应用场景主要是 函数指针的动态绑定,使用该宏参数,可以实现 同类型 函数指针 赋值或者引用的 方便操作。这个后面会有代码详细分析。

2、“##”的作用是将 左右两边的参数做整体字符串拼接替换

不管 ## 左右两边是字母还是数字,最终都是作为 一个整体 拼接成一个字符串。代码如下:

#include <stdio.h>

#include <stdlib.h>

#define FUNC(a) func_##a

void 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_##a

void 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.

给我留言

留言无头像?