EDA365电子工程师网

标题: C语言宏定义中#和##的作用 [打印本页]

作者: zd305    时间: 2016-8-23 18:27
标题: C语言宏定义中#和##的作用
本文由dongeasy.com收集整理,原文链接:http://www.dongeasy.com/software-development/embedded-system/2013.html- M! J; j+ C# [/ [! `( ]1 U
在宏定义中#和##的作用是:前者将宏定义的变量转化为字符串;后者将其前后的两个宏定义中的两个变量无缝拼接在一起转化为字符串。
1.   #: 在宏定义中,将其后的变量,转化为字符串。
eg:  #define  str(s)      #s
输出: helloworld , 就可以通过这样的的调用, printf( str(helloworld) );
2. ## : 在宏定义中,将其前后的两个变量拼接在一起。
eg: #define v(a,b,c,d)       0xa##b##c##d
//将四个字节的十六进制的数据转化为一个十六进制的整型数据
int    a  =  v(CF,AB,B0,BC);   // 即 a = 0xCFABB0BC
3. 两者的共性: 能够阻止宏定义的递归展开。可以通过中间的转换的宏,来实现参数宏的展开。
测试例子:
  • #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;
  • }
    - [5 z2 J, `8 ^: g, O% X1 {; r
测试结果:
  • ~/test$ ./macro_sign
  • path(dir,name) = /mnt/sd/
  • test(name) = NAME   #宏不会递归展开
  • test(MON) = MON    #可以很方便地实现枚举变量的字符串显示
  • /mnt/sd/kernel.img   # ##符号的特殊用法
    - G: P) H, K+ c. b
实际应用
使用#和##宏符号的作用定义最简单的日志接口,如下:
  • #define SLOG(level,format,args...) \
  •      do{printf("[%s]",#level);printf(format,##args);}while(0), s" A) \1 k6 `  f2 W, T
  • SLOG(ERR,"%s",strerror(errno); // 调用方式,不需要定义ERR宏,接口会自动打印为字符串
    * l5 t% B: s0 G' ^7 G. ~; o$ h
这个宏可以很方便地替换在项目中使用的正式日志接口,用来保持模块的独立性,便于模块的测试。

' h7 s" E2 X- V# @
# l% \* o# }5 Z1 T
% }  L' ?* s5 x% ]9 y. _8 R





欢迎光临 EDA365电子工程师网 (https://bbs.elecnest.cn/) Powered by Discuz! X3.2