在Visual Studio里利用pdb文件进入lib调试方法

本文介绍了如何在Visual Studio中调试静态库(.lib)和动态库(.dll)的代码,包括加载符号文件(.pdb)及源码的具体步骤,并提供了解决方案属性配置的指导。

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

1. 基础知识

静态库和动态库

首先说一下,库的导出分为静态库和动态库。
在这里插入图片描述

导出静态库的话,会生成一个.lib文件,其实就是.obj的集合,.obj又是.cpp编译得到的,所以,静态库里有函数的实现。不过这些实现是二进制的,是不带源码的。使用静态库的时候,需要链接.lib,包含.h。

导出动态库的话,会生成.dll文件和.lib文件,动态库生成的.lib文件会很小,因为这里的.lib只需要指明函数在.dll中的位置就可以了。使用的时候,需要把.dll和程序将要生成的.exe放在一个位置(双击exe运行),或者放在“调试 - 工程目录”指定的位置(在IDE中运行)。当然,如果你把“调试 - 工程目录“设置成$(OutDir),就和exe的输出位置一致了,调试也能运行,双击exe也能运行。

符号文件.pdb

.pdb文件就是所谓的符号文件。在库的编译过程中一同产生,pdb的生成位置和文件名由“链接器 - 调试 - 生成程序数据库文件”决定。这个名字是会写进.dll的,也可以和.dll的名字不一样。例如,dll的名字是a.dll,生成时的符号文件是b.pdb,你在调试时把b.pdb强行改成a.pdb,调试器是不认的。所以,为了调试方便不混淆,我建议把.pdb的文件名设置成和.dll一样。否则debug版和release版的pdb都一个名字,就无法区分了。

.pdb文件里面记载了函数名称和对应的.cpp文件名称,.cpp文件的md5信息。所谓“符号文件”,就是在你调试时用来查找函数对应于哪个.cpp文件哪一行的,好告知调试器跳转过去。
在这里插入图片描述

2. 加载符号

现在假设你已经有一个工程了,可以编译运行。你调用了在.lib中的函数,下了断点,按F11想要步入。

这时有两种情况,第一种是你直接跳转到库的源码了。这里的原理很简单,因为你的pdb已经加载(你把pdb放在调试目录了),pdb里记载了函数所在的cpp,而这个库是你在本机编译的,绝对路径没有改动,调试器直接就找到了对应的cpp,所以就直接跳转了。

而第二种情况,按F11并不能进入到源码,而是直接步过了。如果想进入.lib的源码,需要怎么做呢?

首先需要准备.pdb文件,还有库的源码。

之后要检查符号是否加载。下断点,F5调试。然后“调试 - 窗口 - 模块”打开模块窗口。
在这里插入图片描述
找到第三方dll的名字,我这里是DuiLib_ud.dll,看“符号文件”一栏是空的。说明这个dll的符号文件没有加载。

把.pdb和.dll放在一起。
在这里插入图片描述
再次调试。可以看到符号文件已经加载了。
在这里插入图片描述
其实不和dll放一起也可以。“工具 - 选项 - 符号”,在符号文件位置下面增加路径也可以。不过我不喜欢改动没有移植性的环境选项,更喜欢凡事都用相对路径。顺带一提,通过上面的模块界面,可以加载系统dll的符号文件,调试时可以进入系统dll的汇编。
在这里插入图片描述

3. 加载源码

现在符号文件已经加载了。再次开始调试,在断点处按F11步入。弹出了查找源码的选项。
在这里插入图片描述
在这里你就可以手动指定源码的位置了,不用担心版本出错,有md5校验的,你指定的.cpp如果不是这个库当初生成时的.cpp是通不过的。

不过我不喜欢这种硬编码绝对路径的做法,不优雅。我们点取消,就会看见未找到XXX.cpp界面。展开“源搜索信息”,可以看到调试器都从哪些地方在寻找这个.cpp文件。记住这个界面,如果我们之后指定.cpp路径时不正确,可以在这里来查看。
在这里插入图片描述
之后,把库的源码复制到我们自己的工程目录里。工程文件什么的不用带,只需要.cpp就可以了,理论上.h都不需要。
在这里插入图片描述
之后,在解决方案上右键“属性”,注意是解决方案上右键,不是工程。选择“通用属性 - 调试源文件”,在“包含源代码的目录”里增加我们刚拷进来的库的源代码目录。
在这里插入图片描述
微软说这里的查找源文件功能是不能识别子目录的,所有子目录都要手动加进来。

这里修改了之后,我实验发现要重启VS才生效。再次调试,可以进到库的源码了。在库的源码上悬停,我这里是在UIBase.cpp上悬停,可以看到它找到的源码的文件路径。确认是找到了我们刚放进去的源码。
在这里插入图片描述
本来我还想实验一下。我改了lib_src文件夹的名字,发现它还是能找到源码;我删掉debug文件夹下的内容,它还是能找到;我删掉和exe一块儿生成的.ilk和.pdb,它还是能找到;我删掉.vs隐藏文件夹,它还是能找到;我改动工程路径,它还是能找到。

这就很迷茫了。总之,也许它找到一次之后,查找文件功能就突然逆天了,知道寻找解决方案下面的所有cpp文件吧。

参考

如何调试静态库的代码(libeay32.lib和ssleay32.lib)

在 Visual Studio 调试器(C#、C++、Visual Basic、F#)中指定符号 (.pdb) 和源文件

### 关于AcWing平台上最长公共子序列问题 #### 解决方案概述 针对AcWing平台上的最长公共子序列(LCS)问题,采用动态规划(DP)[^1]是一种高效的方法来解决此类挑战。此方法不仅能够有效地计算两个字符串之间的最大匹配字符数量,而且可以进一步扩展以追踪具体的匹配路径。 #### 动态规划原理说明 通过构建二维表格dp[i][j]表示第一个串前i个字符与第二个串前j个字符的最大匹配数[^2]。当遇到相同字符时,在左上角的基础上加一;如果不同则取上方和左侧较大者继承下来作为当前格子的值。最终整个表填满后的右下角即为所求的结果长度。 #### Python代码实现示例 下面是一个基于上述理论的具体Python程序: ```python def longest_common_subsequence(text1: str, text2: str) -> int: m, n = len(text1), len(text2) dp = [[0] * (n + 1) for _ in range(m + 1)] for i in range(1, m + 1): for j in range(1, n + 1): if text1[i - 1] == text2[j - 1]: dp[i][j] = dp[i - 1][j - 1] + 1 else: dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) return dp[-1][-1] ``` 这段代码实现了寻找两段文字间最长公共子序列的功能,并返回其长度[^3]。 #### 进一步获取具体子序列内容 为了得到实际构成这个最小子序列的内容而不是仅仅知道它的长度,可以在原有基础上增加回溯过程。从`dp[m][n]`出发向左上角遍历直到起点位置,每当发现相等情况就记录对应字母到列表中最后反转即可获得完整的LCS字符串[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值