[转]宏的高级使用 #, ##, __VA_ARGS__, __FILE__, __FUNCTION__

文章目录

  • 一 常见宏概念
  • 二 常见宏的使用
    • 1.字符串化#
    • 2.宏连接符##
    • 3.宏变量
      • 解析
  • 重点:编译过程

一 常见宏概念

先说一下本文中会提到的内容:#,##,__VA_ARGS__, __FILE__, __LINE__ , __FUNCTION__

  • #: 把语言符号转换成字符串 ,字符串化(stringizing)

  • ##: 宏连接符

  • __VA_ARGS__: 可变参数宏(C99编译器标准终于改变了这种局面,它允许你可以定义可变参数宏(variadic macros),这样你就可以使用拥有可以变化的参数表的宏。) 使用 #define Debug(...) printf(__VA_ARGS__)

  • __ __FILE__, __LINE__ , __FUNCTION__:宏变量

二 常见宏的使用

1.字符串化#

假如希望在字符串中包含宏参数,ANSI C允许这样作,在类函数宏的替换部分,#符号用作一个预处理运算符,它可以把语言符号转化程字符串。例如,如果x是一个宏参量,那么#x可以把参数名转化成相应的字符串。该过程称为字符串化(stringizing).

#incldue 
#define PSQR(x) printf("the square of" #x "is %d.\n",(x)*(x))
int main(void)
{
    int y =4;
    PSQR(y);
    PSQR(2+4);
    return 0;
}

输出结果:

the square of y is 16.
the square of 2+4 is 36.

第一次调用宏时使用“y”代替#x;第二次调用时用“2+4"代#x。

2.宏连接符##

代码如下:

[cpp] view plain copy
#include   
#define XNAME(n) x ## n  
#define PRINT_XN(n) printf("x" #n " = %d/n", x ## n);  
int main(void)  
{  
int XNAME(1) = 14; // becomes int x1 = 14;  
int XNAME(2) = 20; // becomes int x2 = 20;  
PRINT_XN(1); // becomes printf("x1 = %d,", x1);  
PRINT_XN(2); // becomes printf("x2 = %d/n", x2);  
return 0;  
}

输出为:x1 = 14, x2 = 20

3.宏变量

先举一个例子,会用到上面这些宏:

[cpp] view plain copy
#define myprintf(...) printk("[lch]:File:%s, Line:%d, Function:%s," \  
     __VA_ARGS__, __FILE__, __LINE__ ,__FUNCTION__);  

此处的 #define的作用是将 myprintf( )换成后面那一大串的内容,而括号内 … 的内容原样抄写在 VA_ARGS 的位置。最终输出如下:

[lch]:File:arch/arm/mach-omap2/board-omap3wscec-camera.c, Line:163, Function:beagle_cam_init,camera init!

解析

  1. __VA_ARGS__:总体来说就是将左边宏中 … 的内容原样抄写在右边 VA_ARGS 所在的位置。它是一个可变参数的宏,是新的C99规范中新增的,目前似乎只有gcc支持(VC从VC2005开始支持)。要注意的是,printf 的输出格式是括号内左边是字符串,右边是变量,而且右变量与左输出格式是一一对应的。所以在上面那个例子中, __VA_ARGS__只能是一些不含任何变量的字符串常量。因为上面的例子中若__VA_ARGS__含有变量,整个printf的输出与变量便不能一一对应,输出会出错。

    如果仅仅是替换函数名,可用如下方式,此时对__VA_ARGS__无任何特殊要求:#define myprintf(…) printk( VA_ARGS),在调试程序时可以这样用:

    [cpp] view plain copy
    #ifndef LOG_NDEBUG_FUNCTION  
    #define LOGFUNC(...) ((void)0)  
    #else  
    #define LOGFUNC(...) (printk(__VA_ARGS__))  
    #endif  
    
  2. __FILE__:宏在预编译时会替换成当前的源文件名

  3. __LINE__:宏在预编译时会替换成当前的行号

  4. __FUNCTION__:宏在预编译时会替换成当前的函数名称

  5. 类似的宏还有__TIME__,__STDC__, __TIMESTAMP__等,就完全当一个变量来使用即可。

重点:编译过程

  1. 扫描解析文件
  2. 预处理(宏在此时处理,该替换的文字会被替换)
  3. 对处理过的源代码进行汇编,输出汇编语言的代码(C语言的控制流程被处理)
  4. 编译为二进制目标文件
  5. 与程序库进行链接,输出最终的程序文件

原文:宏的高级使用 #, ##, VA_ARGS, FILE, FUNCTION

你可能感兴趣的:(c/c++)