__file__和__line__是c++标准预定义宏,编译时由编译器自动替换为当前源文件路径和行号,无运行时开销;常见用法如std::cout

用 __FILE__ 和 __LINE__ 宏最直接
这两个是 C++ 标准预定义宏,编译时由编译器自动替换为当前源文件的绝对路径(或相对路径,取决于编译选项)和行号。它们不是函数调用,不产生运行时开销,也不依赖任何头文件。
常见写法:
std::cout <p>注意点:</p>
-
__FILE__在不同编译器下路径格式可能不同(如 MSVC 默认用反斜杠,GCC/Clang 用正斜杠/),若需统一处理,建议用std::filesystem::path解析 -
__LINE__是整型字面量,可直接参与 constexpr 计算,比如做静态断言:static_assert(__LINE__ > 100, "too early"); - 宏展开发生在预处理阶段,所以它们反映的是宏被写入的位置,不是调用位置——这点在封装日志宏时特别关键
封装成日志宏时,__FILE__ 要截取文件名而非全路径
直接输出 __FILE__ 往往太长(比如 /home/user/project/src/main.cpp),日志里通常只关心 main.cpp。但不能在宏里用 std::string 处理,因为宏展开是纯文本替换,没有运行时能力。
推荐做法是用另一个宏辅助截取:
#define CURRENT_FILE (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 :
strrchr(__FILE__, '\') ? strrchr(__FILE__, '\') + 1 : __FILE__)
#define LOG_INFO() std::cout <p>说明:</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill5502" title="C++ Code Review Master"><img
src="https://img.php.cn/upload/skill/000/000/081/179051228971575.jpg" alt="C++ Code Review Master" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/skill5502" title="C++ Code Review Master" class="overflowclass">C++ Code Review Master</a>
<p class="overflowclass">组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。</p>
</div>
<a rel="nofollow" href="/xiazai/skill5502" title="C++ Code Review Master" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div>
- 这个
CURRENT_FILE是纯宏实现,兼容 C++11 及以上,不依赖 STL 运行时 - 它同时适配 Unix 和 Windows 路径分隔符,但注意:如果
__FILE__是相对路径(如src/util.h),且不含分隔符,就直接用原值 - 某些构建系统(如 Bazel)可能把
__FILE__设为短名(如util.h),此时该宏退化为恒等式,无副作用
想在函数里动态获取?别信运行时反射,C++ 没原生支持
C++ 标准至今(C++23)不提供类似 Python 的 inspect.stack() 或 Rust 的 file!() 运行时求值机制。所谓“动态获取当前行号”本质仍是宏——只是被包装得更隐蔽。
常见误区:
- 写一个普通函数
get_line()试图返回__LINE__:不行,__LINE__在函数定义处展开,不是调用处 - 用
std::source_location(C++20):它确实能获取调用点信息,但必须显式传参,且不是“自动”获取——你得在每个调用点写std::source_location::current() - 示例(C++20):
void log(const char* msg, const std::source_location& loc = std::source_location::current()) {
std::cout <p>注意:<code>std::source_location::current()</code> 是编译器内置魔术,不是普通函数调用;它在模板实例化或宏中行为稳定,但老编译器(如 GCC 10 以下)不支持。</p><h3>调试时打印行号,但发布版要关掉?用条件宏控制</h3><p>日志宏带文件行号会增大二进制体积(字符串字面量增多),调试时有用,上线后可能想裁掉。靠 <code>#ifdef DEBUG</code> 最稳妥:</p><pre class="brush:php;toolbar:false;">#ifdef DEBUG
#define DEBUG_LOG(msg) std::cout <p>要点:</p>
- 不要用
if constexpr或运行时判断来“开关”宏,那无法真正消除字符串字面量 - 如果项目用 CMake,确保
DEBUG宏在 Debug 构建中定义:target_compile_definitions(myapp PRIVATE $:DEBUG>) - 注意宏名冲突:像
LOG这种通用名容易和第三方库(如 glog、spdlog)撞车,建议加项目前缀
实际用的时候,<strong>FILE</strong> 和 <strong>LINE</strong> 看似简单,但宏展开时机、路径分隔符差异、发布版裁剪这些细节,往往在跨平台或长期维护时才暴露出来。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










