C++ std::source_location::current _ 获取当前行号与文件名【详解】

风杰酱_1106

风杰酱_1106

2026-04-11

713人浏览

原创

std::source_location::current() 返回行号1是因为它在宏展开位置由编译器内联注入位置信息;若封装成普通函数则记录函数定义处而非调用处的行号,必须在调用现场直接使用或通过默认参数/宏传递。

c++ std::source_location::current _ 获取当前行号与文件名【详解】

std::source_location::current() 在 C++20 中为什么返回的行号总是 1?

因为 std::source_location::current() 是一个 编译期内联函数,它不“运行”在调用点,而是由编译器在**宏展开位置**直接注入当前源码位置信息。如果你把它封装成普通函数再调用,比如:

std::source_location get_loc() {
    return std::source_location::current(); // ❌ 这里记录的是 get_loc 函数体内的行号(通常是定义该函数的第一行)
}

那返回的 line() 就是 get_loc 函数体所在的行,而非调用 get_loc() 的那一行。这是最常踩的坑。

  • 必须在需要记录位置的**调用现场直接使用** std::source_location::current()
  • 不能跨函数传递——除非你把 std::source_location 当作参数显式传入,并在调用方构造
  • 所有主流编译器(GCC 11+、Clang 12+、MSVC 19.30+)都遵循这一行为,不是 bug,是设计使然

如何安全地把 source_location 传进日志函数?

典型做法是让日志函数接收一个默认参数,由编译器在调用点自动填充:

void log(const char* msg, const std::source_location loc = std::source_location::current()) {
    printf("[%s:%d] %s\n", loc.file_name(), loc.line(), msg);
}

这样每次调用 log("error"),loc 就精准对应到 log("error") 所在的文件和行号。

C++14
C++14

C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。

下载
  • 默认参数必须是字面量表达式,std::source_location::current() 是唯一被允许的非常量默认值
  • 不能写成 auto loc = std::source_location::current() 再传参——这又掉回上一节的坑里
  • 如果函数是模板或 inline,依然有效;但若函数声明在头文件外且未 inline,可能因 ODR 导致多个 TU 中生成不同位置信息(极少见,但需留意)

file_name() 返回的路径为什么很长甚至含绝对路径?

std::source_location::file_name() 返回的是编译器内部记录的完整路径字符串,取决于你编译时的 -I、工作目录和源文件引用方式。GCC/Clang 默认输出绝对路径,MSVC 可能相对路径更常见。

  • 不要依赖路径格式做字符串匹配(比如 strstr(loc.file_name(), "src/")),它不稳定
  • 如需裁剪,建议在日志函数里用 std::filesystem::path(loc.file_name()).filename().string()(C++17+)提取文件名
  • 某些构建系统(如 Bazel、CMake with compile_options("$<join:>")</join:>)可配合编译器 flag 控制路径标准化,但非标准行为

在宏里封装 source_location 会不会破坏调试信息?

不会,而且这是推荐做法——宏能确保 current() 展开在用户代码行:

#define LOG(msg) do { \
    ::log(msg, std::source_location::current()); \
} while(0)

调用 LOG("timeout") 时,std::source_location::current() 确实捕获的是 LOG("timeout") 所在行。

  • 宏比默认参数更灵活:可同时注入 __func__、自定义级别、时间戳等
  • 注意避免宏中出现分号冲突,用 do { ... } while(0) 包裹是稳妥选择
  • 如果用了 constexpr 函数封装,只要它不带函数调用(即纯内联展开),也可行;但一旦有函数调用层级,位置就偏移了

真正难处理的不是语法,而是当 source_location 被无意中“抬升”到封装层时,你看到的行号和预期差了七八行却查不出原因——这时候要立刻检查是否多套了一层函数调用。

C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!

相关专题

更多
string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.02

6359

3

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

2023.10.24

6064

49

while的用法
while的用法

while的用法是“while 条件: 代码块”,条件是一个表达式,当条件为真时,执行代码块,然后再次判断条件是否为真,如果为真则继续执行代码块,直到条件为假为止。本专题为大家提供while相关的文章、下载、课程内容,供大家免费下载体验。

2023.09.25

354

5

scripterror怎么解决
scripterror怎么解决

scripterror的解决办法有检查语法、文件路径、检查网络连接、浏览器兼容性、使用try-catch语句、使用开发者工具进行调试、更新浏览器和JavaScript库或寻求专业帮助等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2023.10.18

989

5

500error怎么解决
500error怎么解决

500error的解决办法有检查服务器日志、检查代码、检查服务器配置、更新软件版本、重新启动服务、调试代码和寻求帮助等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2023.10.25

2940

5

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.03

1738

5

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

2023.09.04

2684

5

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

2023.10.24

6064

49

字符串介绍
字符串介绍

字符串是一种数据类型,它可以是任何文本,包括字母、数字、符号等。字符串可以由不同的字符组成,例如空格、标点符号、数字等。在编程中,字符串通常用引号括起来,如单引号、双引号或反引号。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

2023.11.24

5669

6

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C++ Core Guidelines
C++ Core Guidelines

共0课时 | 0人学习

C++ Reference
C++ Reference

共0课时 | 0人学习

C++ 官方标准说明
C++ 官方标准说明

共0课时 | 0人学习