宏 __FILE__,__LINE__,#line,__func__

本文详细解析了C语言中的__FILE__、__LINE__、__func__的用途,包括它们如何在源文件中指示文件名、行号和函数名,以及在不同编译环境下(如gcc和Windows的vc6.0)的使用案例和执行结果。同时,文章还提到了这些关键字的大小写敏感性和相关特性。

原文:http://blog.youkuaiyun.com/taric_ma/article/details/7517949


C语言中的__FILE__用以指示本行语句所在源文件的文件名,举例如下(test.c):
  1. #include <stdio.h>
  2. int main()
  3. {
  4. printf("%s\n",__FILE__);
  5. }
在gcc编译生成a.out,执行后输出结果为:
test.c
在windows的vc6.0下编译执行结果为:
c:\documents and settings\administrator\桌面\test.c


----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


C语言中的__LINE__用以指示本行语句在源文件中的位置信息,举例如下:

  1. #include <stdio.h>



  2. main()
  3. {
  4. printf("%d\n",__LINE__);
  5. printf("%d\n",__LINE__);
  6. printf("%d\n",__LINE__);
  7. };
该程序在linux用gcc编译,在windows的vc6.0下编译都可以通过,执行结果都为:
7
8
9

还可以通过语句#line来重新设定__LINE__的值,举例如下:
  1. #include <stdio.h>


  2. #line 200  //指定下一行的__LINE__为200
  3. main()
  4. {
  5. printf("%d\n",__LINE__);
  6. printf("%d\n",__LINE__);
  7. printf("%d\n",__LINE__);
  8. };
编译执行后输出结果为:
202
203
204

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

另外gcc还支持__func__,它指示所在的函数,但是这个关键字不被windows下的vc6.0支持,举例如下:
  1. #include <stdio.h>
  2. void main()
  3. {
  4. printf("this is print by function %s\n",__func__);
  5. }
其编译后输出结果为
this is print by function main




注意 “#line”、 “__LINE__”、 “__FILE__" 及 “__func__" 都是大小写敏感的。

### 参数 `__VA_ARGS__` 的使用方法 在 C 和 C++ 中,可以通过预处理器指令来扩展代码的功能。其中,`__VA_ARGS__` 是一种特殊的语法形式,用于支持 **可变参数**(variadic macros)。这种机制允许开发者创建能够接受任意数量参数的。 #### 基本概念 `__VA_ARGS__` 表示传递给的所有额外参数,在展开时会被替换为实际传入的内容[^1]。它通常与其他操作符一起使用,比如逗号连接器 (`##`) 或其他辅助工具。 以下是关于如何正确使用 `__VA_ARGS__` 的一些核心要点: --- ### 可变参数的基础结构 一个典型的可变参数定义如下所示: ```c #define MACRO_NAME(arg1, arg2, ...) \ some_code(arg1, arg2, __VA_ARGS__) ``` 在这个例子中: - 参数 `arg1` 和 `arg2` 是固定参数; - 使用省略号 `...` 来表示后续可能存在的零个或多个附加参数; - `__VA_ARGS__` 被用来代表这些附加参数的实际值。 当调用此时,可以像函数一样提供不同数量的参数。例如: ```c MACRO_NAME(a, b); MACRO_NAME(a, b, c, d, e); ``` 上述两种情况都会被正确解析并处理。 --- ### 实际案例分析 #### 示例 1:简单的日志记录 下面是一个常见的场景——构建一个带有动态消息的日志打印。 ```c #include <stdio.h> // 日志记录 #define LOG(level, fmt, ...) printf("[%s] " fmt "\n", level, __VA_ARGS__) int main() { LOG("INFO", "This is an informational message."); LOG("ERROR", "An error occurred with code %d.", 404); return 0; } ``` 运行结果将是: ``` [INFO] This is an informational message. [ERROR] An error occurred with code 404. ``` 这里的关键在于通过 `__VA_ARGS__` 将格式化字符串及其对应的变量自动插入到最终生成的代码片段中[^2]。 --- #### 示例 2:条件判断中的应用 另一个典型用途是在某些条件下执行特定逻辑的同时保留灵活性。例如 TensorFlow 提供了一个名为 `OP_REQUIRES_OK` 的[^3],其内部利用了类似的技巧: ```cpp #define OP_REQUIRES_OK(CTX, STATUS) \ do { \ ::tensorflow::Status _status = (STATUS); \ if (!_status.ok()) { \ CTX->CtxFailureWithWarning(__FILE__, __LINE__, _status.message()); \ return; \ } \ } while(false) void ExampleFunction(OpKernelContext* ctx) { OP_REQUIRES_OK(ctx, SomeOperationThatReturnsAStatus()); } ``` 在此处可以看到,`__VA_ARGS__` 替代部分由用户提供自定义状态对象作为输入数据源之一。 --- ### 特殊注意事项 尽管 `__VA_ARGS__` 非常强大,但在实际开发过程中仍需注意几个常见陷阱: 1. 如果没有指定任何额外参数,则可能会导致编译失败或者行为异常。为了避免这种情况发生,可以在设计阶段加入保护措施,例如有条件地移除多余的分隔符 `,`。 解决方案之一就是借助于双井号运算符(`##`)消除不必要的逗号: ```c #define DEBUG_PRINT(fmt, ...) fprintf(stderr, "%s:%d: " fmt "\n", __func__, __LINE__, ##__VA_ARGS__) ``` 2. 不同平台之间可能存在细微差异;因此建议始终查阅目标环境文档确认兼容性问题。 --- ### 总结 综上所述,掌握好 `__VA_ARGS__` 的基本原理以及灵活运用方式对于编写高效简洁且易于维护的程序至关重要。无论是简单调试还是复杂框架集成都离不开这项技术的支持。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值