宏的使用__VA_ARGS__, __FILE__, __FUNCTION__,__TIME__等

本文深入探讨了DebugLog宏在C/C++编程中的使用方式,包括其内部工作原理、关键参数解释及实际应用案例。通过具体实例展示如何在调试过程中有效地记录程序运行状态。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#ifdef DEBUG

#define DebugLog( s, ... ) printf( "<%s:(%d)> %s: %s\n\n", [[[NSString stringWithUTF8String:__FILE__] lastPathComponent] cStringUsingEncoding:NSUTF8StringEncoding], __LINE__,__func__, [[NSString stringWithFormat:(s), ##__VA_ARGS__] cStringUsingEncoding:NSUTF8StringEncoding])

#else

#define DebugLog( s, ... )

#endif


此处 DebugLog( s, ... )的作用是 把它替换成 printf( "<%s:(%d)> %s: %s\n\n", [[[NSString stringWithUTF8String:__FILE__] lastPathComponent] cStringUsingEncoding:NSUTF8StringEncoding], __LINE__,__func__, [[NSString stringWithFormat:(s), ##__VA_ARGS__] cStringUsingEncoding:NSUTF8StringEncoding])


1. __VA_ARGS__:总体来说就是将左边宏中"( s, ... )" 的内容原样抄写在右边 __VA_ARGS__ 所在的位置,它是一个可变参数的宏。要注意的是,printf 的输出格式是括号内左边是字符串,右边是变量,而且右变量与左输出格式是一一对应的,用法和NSLog差不多。

宏前面加上##的作用在于,当可变参数的个数为0时,这里的##起到把前面多余的","去掉的作用,否则会编译出错, 你可以试试。

实现思想就是宏定义中参数列表的最后一个参数为省略号(也就是三个点)。这样预定义宏_ _VA_ARGS_ _就可以被用在替换部分中,替换省略号所代表的字符串

2. __FILE__ :宏在预编译时会替换成当前的源文件名

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

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

5. __TIME__:宏在预编译时会替换成系统的当前时间

6.__TIMESTAMP__:和第五点类似

7.##运算符可以用于类函数宏的替换部分。另外,##还可以用于类对象宏的替换部分。这个运算符把两个语言符号组合成单个语言符号

例:

DebugLog(@"123");


输出:

<ViewController.m:(34)> 11:40:14Tue Jan 12 11:11:16 2016 -[ViewController viewDidLoad]: 123



了解更多:http://www.cnblogs.com/pengyingh/articles/2407265.html



### 关于 `__FUNCTION__` 使用 在 C/C++ 中,`__FUNCTION__` 是一种预定义,用于表示当前函数的名称。它通常被用来调试程序或记录日志以便追踪代码执行路径。 #### 示例代码展示 下面是一个简单的例子来演示如何使用 `__FUNCTION__`: ```c #include <stdio.h> void exampleFunction() { printf("Current function name is: %s\n", __FUNCTION__); } int main() { printf("Main function name is: %s\n", __FUNCTION__); exampleFunction(); return 0; } ``` 运行上述代码会打印出当前正在执行的函数名[^2]。 #### 编译器差异说明 需要注意的是,不同编译器对于获取当前函数名的支持方式有所不同。例如,在 GCC 编译器中可以使用 `__PRETTY_FUNCTION__` 来获得更详细的函数签名信息,而 Visual C++ 则提供了一个名为 `__FUNCSIG__` 的作为替代方案[^1]。 #### 结合其他预定义一起使用的场景 除了单独使用外,还可以将其与其他一些有用的内置结合起来增强功能。比如通过联合运用 `__LINE__`, `__FILE__`, 和 `__FUNCTION__` 可以构建非常详尽的日志消息,这对于错误排查特别有帮助: ```c #define LOG_ERROR(fmt, ...) fprintf(stderr, "[%s:%d - %s()] Error: " fmt "\n", \ __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__) void divide(int a, int b) { if (b == 0) { LOG_ERROR("Division by zero"); return; } printf("%d / %d = %.2f\n", a, b, ((float)a)/b); } int main() { divide(10, 0); return 0; } ``` 在这个例子中,如果发生除零异常,则会在标准错误流上输出包含文件位置以及具体哪个函数触发了这个事件的信息。 #### 特殊情况下的应用——结构体属性设置 虽然这并不直接涉及 `__FUNCTION__` 自身的应用,但是值得注意的是,在某些特定情况下(如利用 GCC 提供的扩展特性),我们也可以借助类似的概念来自定义行为。例如,可以通过指定 `__attribute__((packed))` 让结构体内存布局更加紧凑从而节省空间[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值