工作中如果是c开发的话,经常会用到宏定义,而宏定义中的#和##也会时不时遇到,今天分享这两个符号的作用。
1,# -- 转换成字符串
直接看例子:
#include <stdio.h>
#include <stdlib.h>
#define VAL2STR(VAL) (#VAL)
#define fun_call_rt(func) \
do \
{ \
int ret = func; \
if(ret){printf("%d = %s\n", ret, #func);} \
} while (0);
int func_for_test(int value);
int main()
{
int val = 200;
printf("%s\n", VAL2STR(200));
fun_call_rt(func_for_test(10));
return 0;
}
int func_for_test(int value)
{
if(value == 100)
{
return 0;
}
else
{
return -1;
}
}
我们可以直接用gcc -E 预编译看看宏展开后是什么样的?如用命令 gcc -E test_#.c -o preprocess_test 编译后,我们看最后的代码:
其中的 VAL2STR(200) 被替换成了 ("200"),fun_call_rt(func) 中的 #func 被替换成了 "func_for_test(10)",即都被替换成了字符串,在c语言中应该称为字符数组类型。
在一些公司中类似 fun_call_rt(func) 宏几乎处处可见,在每个函数调用的地方都是这个宏括起来,一旦有错误发生,打印输出一目了然。
2, ## -- 连接两个语句为一个语句
这里所说的语句,可以是函数名,类型名,变量名,但都需要有实际意义,否则就会编译不过,看代码:
#include <stdio.h>
#include <stdlib.h>
#define NAME_JOIN(x,y) x##y
int func_for_test_1();
int main()
{
printf("%p\n", NAME_JOIN(func_for_test, _1));
return 0;
}
int func_for_test_1()
{
return 10;
}
假如我改成 printf("%p\n", NAME_JOIN(func_for_test1, _1)); 在编译的时候会出现错误:
因为 NAME_JOIN(func_for_test1, _1) 只是简单的把两个短语连接为一个短语,而连接后的这个短语是否有效那就要做语法检测了,如上面执行的结果为:打印函数的地址
那如果改成这样:printf("ret = %d\n", NAME_JOIN(func_for_test, _1)()); 就是一个函数调用了,其结果就是:
而有一种情况这个 ## 可能不会是你想要的结果,那就是宏定义里又包含宏定义,如:
#include <stdio.h>
#include <stdlib.h>
#define NUMBER_1 _1
//#define NAME_JOIN(x,y) NAME_JOIN2(x,y)
#define NAME_JOIN(x,y) x##y
int func_for_test(int value);
int func_for_test_1();
int main()
{
printf("ret = %d\n", NAME_JOIN(func_for_test, NUMBER_1)());
return 0;
}
int func_for_test_1()
{
return 10;
}
NAME_JOIN(func_for_test, NUMBER_1) 宏定义里又包含了宏 NUMBER_1,这样编译会出现什么问题呢?
可以看到 NUMBER_1 没有被展开,我们想要的是它被展开为 -1,即 func_for_test_1。处理办法就是再多加一个宏定义,如:
#include <stdio.h>
#include <stdlib.h>
#define NUMBER_1 _1
#define NAME_JOIN(x,y) NAME_JOIN2(x,y)
#define NAME_JOIN2(x,y) x##y
int func_for_test(int value);
int func_for_test_1();
int main()
{
printf("ret = %d\n", NAME_JOIN(func_for_test, NUMBER_1)());
return 0;
}
int func_for_test_1()
{
return 10;
}
这样就能正确展开,编译成功。