`

宏的高级使用--##,__VA_ARGS__, __FILE__, __FUNCTION__等

    博客分类:
  • c++
 
阅读更多

先说一下本文中会提到的内容:##,__VA_ARGS__, __FILE__, __LINE__ , __FUNCTION__等
宏变量:
先举一个例子,会用到上面这些宏:

[cpp] view plaincopy
 
  1. #define myprintf(...) printk("[lch]:File:%s, Line:%d, Function:%s," \  
  2.      __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 plaincopy
 
  1. #ifndef LOG_NDEBUG_FUNCTION  
  2. #define LOGFUNC(...) ((void)0)  
  3. #else  
  4. #define LOGFUNC(...) (printk(__VA_ARGS__))  
  5. #endif  

2) __FILE__ :宏在预编译时会替换成当前的源文件名
3) __LINE__:宏在预编译时会替换成当前的行号
4) __FUNCTION__:宏在预编译时会替换成当前的函数名称
5)类似的宏还有 __TIME__,__STDC__, __TIMESTAMP__等,就完全当一个变量来使用即可。

宏连接符##:
举个例子:宏定义为#define XNAME(n) x##n,代码为:XNAME(4),则在预编译时,宏发现XNAME(4)与XNAME(n)匹配,则令 n 为 4,然后将右边的n的内容也变为4,然后将整个XNAME(4)替换为 x##n,亦即 x4,故 最终结果为 XNAME(4) 变为 x4.
代码如下:

[cpp] view plaincopy
 
  1. #include <stdio.h>  
  2. #define XNAME(n) x ## n  
  3. #define PRINT_XN(n) printf("x" #n " = %d/n", x ## n);  
  4. int main(void)  
  5. {  
  6. int XNAME(1) = 14; // becomes int x1 = 14;  
  7. int XNAME(2) = 20; // becomes int x2 = 20;  
  8. PRINT_XN(1); // becomes printf("x1 = %d,", x1);  
  9. PRINT_XN(2); // becomes printf("x2 = %d/n", x2);  
  10. return 0;  
  11. }  

输出为:x1 = 14, x2 = 20


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

分享到:
评论

相关推荐

    __VA_ARGS__用法

    通过使用 `__VA_ARGS__` 和其他几个预处理宏(`__FILE__`, `__LINE__`, `__FUNCTION__`),我们可以非常方便地自定义调试信息的输出。这种方法不仅提高了代码的可读性和可维护性,还增加了调试信息输出的灵活性,...

    C++ 自定义调试信息的输出.doc

    #define qWiFiDebug(format, ...) qDebug("[WiFi] " format " File:%s, Line:%d, Function:%s", ##__VA_ARGS__, __FILE__, __LINE__, __FUNCTION__) ``` 这个宏使用了几个关键的预处理器宏: 1. `__VA_ARGS__`:这...

    Linux内核模块编程

    - `#define kthread_run(threadfn, data, namefmt, ...) \ ({ \ struct task_struct *__k = kthread_create(threadfn, data, namefmt, ##__VA_ARGS__); \ if (!IS_ERR(__k)) \ wake_up_process(__k); \ __k; \ })` ...

    keil中使用printf通过串口输出字符的方法

    #define PRINT_Log(...) printf(__VA_ARGS__) #define PRINT_Err(rc) printf("ERROR: In %s at Line %u - rc = %d\n", __FUNCTION__, __LINE__, rc) #else #define PRINT_Log(...) do {} while(0) #define ...

    linux内核 0.11版本源码 带中文注释

    // 类型(va_list)和三个宏(va_start, va_arg 和va_end),vsprintf、 // vprintf、vfprintf。 #include #include &lt;fcntl.h&gt; // 文件控制头文件。用于文件及其描述符的操作控制常数符号的定义。 #include ...

    xcode-macros-cheatsheet.pdf.zip_Windows编程_Objective-C_

    4. **函数宏**:虽然Objective-C有方法(Method),但有时也会使用函数宏来实现简单的功能,如`#define NSLog(...) NSLog(__VA_ARGS__)`。 四、Xcode宏速查表内容 这份速查表涵盖了Xcode中常用的宏和快捷键,包括...

    c++ 编程 几个有用的宏详解

    在C++编程中,宏是一种强大的工具,它们允许程序员在编译时进行...然而,过度使用宏可能会导致代码难以理解和维护,因此在使用时应谨慎,并尽可能利用C++的其他特性,如模板和异常处理,以提高代码的清晰度和安全性。

    MTMacrosRepo:常用宏定义

    fprintf(stderr, format, ##__VA_ARGS__); \ fprintf(stderr, "\n"); \ } while(0) ``` 这个宏提供了一个自定义的日志打印功能,包含了文件名、行号和函数名,便于调试。 此外,MTMacrosRepo可能还包括一些实用的...

    嵌入式软件调试专题2:printf函数打印高阶技巧

    例如,可以定义`DEBUG_INFO`、`DEBUG_WARNING`、`DEBUG_ERROR`等宏,根据不同的等级选择打印。 ```c #define DEBUG_INFO 1 #define DEBUG_WARNING 2 #define DEBUG_ERROR 3 void debug_print(int level, const ...

    C语言的那些小秘密之变参函数的实现

    .file "varargs.c" .text .globl sum .type sum, @function sum: pushl %ebp movl %esp, %ebp subl $16, %esp movl $0, -4(%ebp) movl $0, -8(%ebp) movl $0, -12(%ebp) leal 12(%ebp), %eax movl %eax, -12...

Global site tag (gtag.js) - Google Analytics