一.独立执行体{}和闭包表达式({})
1.独立执行体{}
void Func(void)
{
//函数代码
}
一般我们认为函数声明(上述的void Func(void))和{}是一个整体,一个构成了一个函数,但其实并不完全是这样,C语言中{}是独立的,叫做独立执行体或者
独立代码段,我们可以在宏定义中使用{},或者在函数内部包含第二个{},如下所示:
void Fun(void)
{
int a = 0;
xxx;//函数代码
{ //{}中代码独立,可以定义变量,执行函数甚至定义函数
int b = 0;
xxx; //函数代码
}
}
#define CAL_CHKSUM(buf,len) { \
(int i=0,sum=0 for(i=0;i<len;i++) sum+=buf[i]; \
}
知道这个以后我们就可以直接在宏定义中实现一些简单函数的功能了,比如if else的判断逻辑。但是想要执行一个返回计算值的函数功能还是不可以的,因为宏定义中不能用return(return后程序会返回到LR所指向的位置)。那对于这个问题有什么办法呢?这就引入了闭包表达式({ })。
2.闭包表达式({})
闭包表达式就是在独立执行体的外部加了一个小括号,他的作用是可以把{}表达式化,什么意思呢?举个例子:
#define CAL_CHKSUM(buf,len) (
{int i=0,sum=0;for(i=0;i<len;i++)sum+=buf[i];sum;}//把独立执行体中的最后一个sum;的内容表达式化
//这个时候宏定义就相当于返回了sum的值
)
uint8_t Val[3] = {1,2,3};
result = CAL_CHKSUM(Val,3);
其实就是闭包表达式把{}中的最后一个内容,变成了"=sum"
二.串化符‘#’及连接符"##"
1.串化符#的使用
先引入一个例子,比如我们想用一个宏,然后用printf函数打印宏的内容,我们会怎么做呢?
#define TO_STRING(X) ("X")
int main(void)
{
printf(TO_STRING("123456789"));
}
我们期望的结果是打印123456789,实际运行打印的是X,并没有达到我们预想的结果。为什么呢?因为宏有个规定,就是宏里面“”包含的内容不会被替换。那我们要怎么解决这个问题呢?这就需要用到串化#,如下所示
#define TO_STRING(X) #X // 串化
int main(void)
{
printf(TO_STRING("123456789"));
}
这个时候打印的就是123456789
2.连接符##
连接符的作用是可以把宏定义中的内容按照文本连接起来,比如:
#define CONNECT_STRING(a, b) (a#b)
int main(void)
{
printf("value=%d\n", CONNECT_STRING(10, 5));
return 0;
}
其中CONNECT_STRING宏定义将两个参数直接拼接在一起,所以在main函数中调用CONNECT_STRING(10, 5)相当于105,所以输出为105。
再举个例子:
#define VAR(x,y) (x##y)
int main()
{
int x1=1,x2=2,x3=3;
int abcd = 100;
printf("%d\n",VAR(x,1)); // 输出x1的值
printf("%d\n",VAR(ab,cd)); // 输出abcd的值
return 0;
}
3.注意事项
当宏参数是另一个宏的时候,凡是宏定义中有#、##的地方,宏参数不会再展开,比如
#include<stdio.h>
#define TO_STRING(s) #s
#define VALUE 100
int main(void)
{
printf(TO_STRING(VALUE));
printf("\n");
return 0;
}
在这个程序中,预处理器首先遇到TO_STRING(VALUE)会替换为#VALUE,然后再替换为"100",所以最终输出的内容是字符串100,回车之后再输出一个换行符。