当前位置: 首页 > news >正文

C++ 的 source_location

1 __FILE__ 和 __LINE__

​ 你一定看过这样的代码:

printf("Internal error at \"%s\" on line %d.\n", __FILE__, __LINE__); 

这行代码的作用就是打印出 printf() 函数调用发生时所在的源代码文件名(包含路径)和这行代码在这个源代码文件中的行数。__FILE____LINE__ 是 C 语言定义的标准预定义宏,编译器会在编译阶段将其展开替换成实际的位置信息。C99 又增加了一个表示当前函数名的宏,就是 __func__,有一些编译器,比如 GCC 也会使用 __FUNCTION_,除了一些细微的语义差别之外,它们的内容展开结果是一样的。

void ProcessLog(t) {printf("error at function: %s\n", __func__); //error at function: ProcessLog
}

2 #line 指令

​ 正常情况下,__FILE____LINE__ 表示的就是调用发生的地方的信息,但是也有例外。在一些复杂系统的编译体系中,部分源代码是通过脚本动态生成的(根据 OS、依赖库或其他信息动态生成支撑层代码),这种情况下预编译程序在替换这两个宏的时候,转换的位置信息与最终的源代码信息可能不一致,导致 C 的代码在脚本中的实际位置可能存在偏差。另外就是源代码文件的名称可能是动态拼接出来的,并不是预处理程序所感知的那个文件名,使得__FILE__的结果也与实际文件名不一致 。

​ 在这种情况下,为了让编译器最终得到准确的信息,需要使用#line预编译指令调整文件名和代码行数信息,这个指令的命令格式是(其中 filename 参数是可选参数):

#line linenum [filename]

linenum 是一个非负整数,表示从这个位置开始,这个文件的代码行从 linenum 指定的数字开始计数。比如这个例子:

#line 200 int main() {printf("Internal error at line %d\n", __LINE__); 
}

printf() 函数输出的结果是:

Internal error at line 203

​ 因为#line是预编译指令,它只影响从这行指令之后的代码中的预编译宏,对这条指令代码位置之前出现的__FILE____LINE__ 没有影响,比如这个例子:

void ProcessLog() {printf("error at function %s (%d).\n", __func__, __LINE__);
}#line 200 int main() {ProcessLog();printf("Internal error at line %d.\n", __LINE__); 
}

最终的输出结果是:

error at function ProcessLog (15).
Internal error at line 204.

可见,ProcessLog() 函数中的__LINE__没有受到这条指令的影响。

​ 如果要调整文件的名字,可以这样使用#line指令:

#line 200 "testfile.cpp"int main() {printf("Internal error at \"%s\" on line %d.\n", __FILE__, __LINE__); 
}

最后的输出结果是:

Internal error at "E:\workspace\01 Test\sl\testfile.cpp" on line 203.

3 std::source_location

​ C++ 也从 C 继承了这些预定义宏,在 C++ 代码中仍然可以使用它们。不过,C++ 20 提供了一个名为 std::source_location 的类,用于表示源代码相关的信息,比如文件名、行号、函数名等等。传统上使用__FILE____LINE__的地方,都可以用这个类代替,并且使用 std::source_location 可以获得更多信息,是更好的选择。

​ std::source_location 的基本用法就是通过这个类的静态函数 current() 可以获得当前调用位置的信息,然后使用 file_name()、line() 等成员方法获取这些信息:

void ProcessLog(const std::string_view message) {const std::source_location location = std::source_location::current();std::cout << "file: "<< location.file_name() << "("<< location.line() << ":"<< location.column() << ") `"<< location.function_name() << "`: "<< message << std::endl;
}

​ 除了多了一个 column 信息,std::source_location 的好处在什么地方?好处就是 std::source_location 能表示更多信息,比如函数,传统的__func__只能得到函数的基本信息,即函数的名称,而 std::source_location 类的 function_name() 可以获得更多的信息:

void ProcessLog(const std::string_view message) {const std::source_location location = std::source_location::current();std::cout << "function: " << location.function_name() << ", " << message << '\n';
}int main(int, char* []) {ProcessLog("Message");
}

上面的代码输出的信息是:

function: void log(std::string_view), Message

函数名包含详细的签名信息。对于函数模板,还会输出模板参数的替换和匹配信息,比如这段代码:

using namespace std::literals;template <typename T> 
void ProcessLog(T x) {const std::source_location location = std::source_location::current();std::cout << "function: " << location.function_name() << ", " << x << '\n';}int main(int, char* []) {ProcessLog("Message"s);
}

代码中的函数模板替换后模板参数 T 的类型就是 std::string,function_name() 的输出信息也包含这部分内容:

function: void ProcessLog(T) [with T = std::basic_string<char>], Message

​ 最后,说重点,第 2 节介绍的#line指令对 std::source_location 也会产生影响,所以,你应该能猜到是什么原因。还有一点就是,目前并不是所有的编译器都支持输出更详细的函数信息,尤其是函数模板参数的替换结果,经过测试,GCC 11 以后的版本支持。

4 参考资料

https://en.cppreference.com/w/cpp/preprocessor/line

https://gcc.gnu.org/onlinedocs/cpp/Line-Control.html#Line-Control

https://en.cppreference.com/w/cpp/utility/source_location

关注作者的算法专栏
https://blog.csdn.net/orbit/category_10400723.html

关注作者的出版物《算法的乐趣(第二版)》
https://www.ituring.com.cn/book/3180

相关文章:

C++ 的 source_location

1 __FILE__ 和 __LINE__ ​ 你一定看过这样的代码&#xff1a; printf("Internal error at \"%s\" on line %d.\n", __FILE__, __LINE__); 这行代码的作用就是打印出 printf() 函数调用发生时所在的源代码文件名&#xff08;包含路径&#xff09;和这行代…...

[python SQLAlchemy数据库操作入门]-14.实时数据采集 记录股市动态

哈喽,大家好,我是木头左! 要使用 SQLAlchemy 进行实时数据采集,首先需要搭建相应的开发环境。以下是所需的主要步骤: 安装 Python:确保你的系统上已经安装了 Python,推荐使用 Python 3.x 版本。创建虚拟环境:为了隔离项目依赖,建议为每个项目创建一个虚拟环境。可以使…...

`we_chat_union_id IS NOT NULL` 和 `we_chat_union_id != ‘‘` 这两个条件之间的区别

文章目录 1、什么是空字符串&#xff1f;2、两个引号之间加上空格 好的&#xff0c;我们来详细解释一下 we_chat_union_id IS NOT NULL 和 we_chat_union_id ! 这两个条件之间的区别&#xff0c;以及它们在 SQL 查询中的作用&#xff1a; 1. we_chat_union_id IS NOT NULL 含…...

【和春笋一起学C++】文本输入与读取

前言&#xff1a;前面学习了while语句后&#xff0c;下面用while语句实现一个重要的功能&#xff0c;逐字符的读取键盘输入的字符序列&#xff0c;并输出到显示屏上。 准备知识&#xff1a; C的输入输出包含以下3方面的内容&#xff1a; 对系统指定的标准设备的输入和输出。即…...

D类音频应用EMI管理

1、前言 对于EMI&#xff0c;首先需要理解天线。频率和波长之间的关系&#xff0c;如下图所示。   作为有效天线所需的最短长度是λ/4。在空气中&#xff0c;介电常数是1&#xff0c;但是在FR4或玻璃环氧PCB的情况下&#xff0c;介电常数大约4.8。这种效应会导致信号在FR4材…...

第N8周:使用Word2vec实现文本分类

文章目录 一、数据预处理1.加载数据2.构建词典3.生成数据批次和迭代器 二、模型构建1.搭建模型2.初始化模型3.定义训练与评估函数 三、训练模型1.拆分数据集并运行模型 四、总结 &#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&a…...

100天精通Python(爬虫篇)——第113天:爬虫基础模块之urllib详细教程大全

文章目录 1. urllib概述2. urllib.request模块 1. urllib.request.urlopen()2. urllib.request.urlretrieve()3. urllib.request.Request()4. urllib.request.install_opener()5. urllib.request.build_opener()6. urllib.request.AbstractBasicAuthHandler7. urllib.request.…...

光谱相机与普通相机的区别

一、成像目的 普通相机&#xff1a;主要目的是记录物体的外观形态&#xff0c;生成人眼可见的、直观的二维图像&#xff0c;重点在于还原物体的形状、颜色和纹理等视觉特征&#xff0c;以供人们进行观赏、记录场景或人物等用途。例如&#xff0c;拍摄旅游风景照片、人物肖像等…...

Mysql数据 新增、修改和删除操作时,这些变化如何被转换为Kafka消息?

Mysql数据 新增、修改和删除操作时,这些变化如何被转换为Kafka消息? 为了在FlinkCDC中配置MySQL同步到Kafka,并采用debezium-json数据格式,我们需要了解当执行新增、修改和删除操作时,这些变化如何被转换为Kafka消息。下面我们将详细介绍这些变化情况,并提供具体的数据样…...

《Python 机器视觉:开启智能视觉新时代》

《Python 机器视觉&#xff1a;开启智能视觉新时代》 一、Python 机器视觉的基石&#xff08;一&#xff09;关键库的强大力量&#xff08;二&#xff09;环境搭建的便捷路径 二、核心功能与奇妙应用&#xff08;一&#xff09;图像的奇幻处理&#xff08;二&#xff09;目标检…...

uniapp实现为微信小程序扫一扫的功能

引言 随着微信小程序的快速发展,越来越多的开发者开始关注和学习微信小程序的开发。其中,微信小程序的扫一扫功能是非常常用且实用的功能之一。通过扫描二维码,用户可以获取到相关的信息或者实现特定的功能。 正文 在过去,开发者需要使用微信开发者工具以及相关的开发文档…...

【微信小程序】4plus|搜索框-历史搜索 | 我的咖啡店-综合实训

升级版1-清空全部的再次确认 实现功能: 历史搜索记录展示-历史搜索记录展示10条点击跳转-点击历史搜索记录可同步到搜索框并自动搜索全部删除-可一次性全部删除历史搜索记录全部删除-有再次确认操作展示 进行搜索后留下搜索记录 点击垃圾桶图标,显示【清空全部】 点击【清…...

使用FFmpeg进行拉流和推流操作

FFmpeg是一款强大的多媒体处理工具&#xff0c;可以用于视频的录制、转换、推流和拉流等操作。下面将详细介绍如何使用FFmpeg进行拉流和推流操作。 1. FFmpeg推流操作 推流是将本地的音视频流推送到流媒体服务器上&#xff0c;例如主播将本地电脑上的画面推流到直播平台的流媒…...

Unity微信小游戏接入开放数据域

demo地址&#xff1a;https://github.com/wechat-miniprogram/minigame-unity-webgl-transform/tree/main/Demo/Ranking 官方说明&#xff1a; https://github.com/wechat-miniprogram/minigame-unity-webgl-transform/blob/main/Design/OpenData.md 准备一个Canvas&#xff0c…...

Spring Boot的开发工具(DevTools)模块中的热更新特性导致的问题

问题&#xff1a; java.lang.ClassCastException: class cn.best.scholarflow.framework.system.domain.entity.SysUser cannot be cast to class cn.best.scholarflow.framework.system.domain.entity.SysUser (cn.best.scholarflow.framework.system.domain.…...

Elasticsearch安装和数据迁移

Elasticsearch安装和数据迁移 Elasticsearch安装 下载并解压Elasticsearch 首先下载Elasticsearch的tar.gz文件&#xff0c;并将其解压&#xff1a; wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.8.2-linux-x86_64.tar.gz tar -xzf elastics…...

Numpy指南:解锁Python多维数组与矩阵运算(下)

文章一览 前言一、排序1.1 numpy.sort1.2 numpy.argsort1.3 numpy.lexsort 二、数组操作2.1 数组元素迭代2.2 数值舍入计算2.3数值取整2.4 数组去重2.5 数组拼接2.6 数组行列交换 三、文件读写3.1 np.fromfile() 读文件3.2 np.loadtxt() 读文件3.3 用 csv 模块逐行处理 CSV 格式…...

路由器刷机TP-Link tp-link-WDR5660 路由器升级宽带速度

何在路由器上设置代理服务器&#xff1f; 如何在路由器上设置代理服务器&#xff1f; 让所有连接到该路由器的设备都能够享受代理服务器的好处是一个不错的选择&#xff0c;特别是当需要访问特定的网站或加速网络连接的时候。下面是一些您可以跟随的步骤&#xff0c;使用路由器…...

VB.NET在 Excel 二次开发中的全面应用

摘要&#xff1a; 本文详细阐述了如何运用VB.NET进行 Excel 的二次开发。首先介绍了开发环境的搭建&#xff0c;包括安装 Visual Studio 及引用 Excel 对象库。接着深入探讨了各种基础操作&#xff0c;如创建 Excel 应用程序对象、打开与操作工作簿、处理工作表与单元格数据等。…...

uni-app使用组件button遇到的问题

在HBuilder X工具中新建一个空白项目&#xff0c; 1、新建一个about页 然后在pages.json文件里加上路由 2、然后看下导航的方法&#xff0c;发现找不到navigateTo方法 参考&#xff1a;button | uni-app官网 第3行和第4行的代码倒是没问题的&#xff0c;第5行的代码有问题执行…...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…...

变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析

一、变量声明设计&#xff1a;let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性&#xff0c;这种设计体现了语言的核心哲学。以下是深度解析&#xff1a; 1.1 设计理念剖析 安全优先原则&#xff1a;默认不可变强制开发者明确声明意图 let x 5; …...

python打卡day49

知识点回顾&#xff1a; 通道注意力模块复习空间注意力模块CBAM的定义 作业&#xff1a;尝试对今天的模型检查参数数目&#xff0c;并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...

【WiFi帧结构】

文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成&#xff1a;MAC头部frame bodyFCS&#xff0c;其中MAC是固定格式的&#xff0c;frame body是可变长度。 MAC头部有frame control&#xff0c;duration&#xff0c;address1&#xff0c;address2&#xff0c;addre…...

华为OD机试-食堂供餐-二分法

import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...

NLP学习路线图(二十三):长短期记忆网络(LSTM)

在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...

springboot整合VUE之在线教育管理系统简介

可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生&#xff0c;小白用户&#xff0c;想学习知识的 有点基础&#xff0c;想要通过项…...

苹果AI眼镜:从“工具”到“社交姿态”的范式革命——重新定义AI交互入口的未来机会

在2025年的AI硬件浪潮中,苹果AI眼镜(Apple Glasses)正在引发一场关于“人机交互形态”的深度思考。它并非简单地替代AirPods或Apple Watch,而是开辟了一个全新的、日常可接受的AI入口。其核心价值不在于功能的堆叠,而在于如何通过形态设计打破社交壁垒,成为用户“全天佩戴…...

uniapp 实现腾讯云IM群文件上传下载功能

UniApp 集成腾讯云IM实现群文件上传下载功能全攻略 一、功能背景与技术选型 在团队协作场景中&#xff0c;群文件共享是核心需求之一。本文将介绍如何基于腾讯云IMCOS&#xff0c;在uniapp中实现&#xff1a; 群内文件上传/下载文件元数据管理下载进度追踪跨平台文件预览 二…...

Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术解析

Java求职者面试指南&#xff1a;Spring、Spring Boot、Spring MVC与MyBatis技术解析 一、第一轮基础概念问题 1. Spring框架的核心容器是什么&#xff1f;它的作用是什么&#xff1f; Spring框架的核心容器是IoC&#xff08;控制反转&#xff09;容器。它的主要作用是管理对…...