C语言宏定义中#和##的作用

在宏定义中#和##的作用是:前者将宏定义的变量转化为字符串;后者将其前后的两个宏定义中的两个变量无缝拼接在一起转化为字符串。

1.   #: 在宏定义中,将其后的变量,转化为字符串。

[c]#define  str(s)      #s [/c]

输出: helloworld , 就可以通过这样的的调用, printf( str(helloworld) );

2. ## : 在宏定义中,将其前后的两个变量拼接在一起。

[c] #define v(a,b,c,d)       0xa##b##c##d   [/c]

//将四个字节的十六进制的数据转化为一个十六进制的整型数据

[c]int    a  =  v(CF,AB,B0,BC);   // 即 a = 0xCFABB0BC[/c]

3. 两者的共性: 能够阻止宏定义的递归展开。可以通过中间的转换的宏,来实现参数宏的展开。

测试例子:

[c]#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define ROOT "/mnt/sd/"
#define NAME "kernel.img"

#define path(dir,name) dir##name
#define print(format,args...) printf(format,##args)
#define test(name) #name

enum
{
MON = 1,
TUE = 2,
SUN = 7
};

int main(int argc, char *argv[])
{
//printf("macro PATH = %s\n", PATH);
//printf("path(dir,name) = %s\n", path(ROOT,NAME));
printf("path(dir,name) = %s\n", path(RO,OT));

//printf("macro TEST = %s\n", TEST);
printf("test(name) = %s\n", test(NAME));
printf("test(MON) = %s\n", test(MON));
//printf("#MON = %s\n", #MON);

print("%s%s\n", ROOT,NAME);

return 0;
}[/c]

测试结果:

[c]~/test$ ./macro_sign
path(dir,name) = /mnt/sd/
test(name) = NAME #宏不会递归展开
test(MON) = MON #可以很方便地实现枚举变量的字符串显示
/mnt/sd/kernel.img # ##符号的特殊用法[/c]

实际应用

使用#和##宏符号的作用定义最简单的日志接口,如下:

[c]#define SLOG(level,format,args...) \
do{printf("[%s]",#level);printf(format,##args);}while(0)
SLOG(ERR,"%s",strerror(errno); // 调用方式,不需要定义ERR宏,接口会自动打印为字符串[/c]

这个宏可以很方便地替换在项目中使用的正式日志接口,用来保持模块的独立性,便于模块的测试。

static、extern分析总结 嵌入式系统

static、extern分析总结

对于写了很多小程序的人,可能static和extern都用的很少,因为static和extern通常在工程量很大时候才能体现优势很必要性,这就不奇怪Linux内核代码中“泛滥”着这两个关键词,而且据我...
PIC单片机上可以使用的RTOS 嵌入式开发

PIC单片机上可以使用的RTOS

PIC单片机上面可以使用的RTOS是比较少的,开源的就更少了。FreeRTOS虽然也支持PIC,但是因为需要的资源较多,所以只能在少数高端PIC单片机上使用。 OSA是在PIC单片机上使用的开源RTO...