如何快速定位一个函数的返回点
如何快速定位一个函数的返回点,这对于一个比较短小精悍的函数来讲,从来就不是问题,但是假设我们有一个名为LongFunction的1000行长的函数, 调用如下:
1 2 | bool bSuccess = LongFunction(); assert (bSuccess); |
在运行中第二行弹出一个assert,我们知道肯定是LongFunction内部运行中出了什么问题导致其返回false。那么它内部出了什么问题,是在哪一行出错导致返回的?这恐怕不是一件容易的事,要知道这是一个1000行的函数,而且极有可能有很多的返回点。
我想这应该是我们日常工作中常见的问题,1000行的长函数在一些大型的系统中,老代码中应该还是不少见的。当然,有些朋友会强烈的认为这样的函数必须要重构,理由是~~~(此处略去500字)。的确,重构的好处是显而易见的,但很多时候由于资源,时间以及复杂度上的考虑,是不被采纳的。所以这里我们不考虑重构,只想找出一个能快速定位到函数返回点的方法。
我们先来分析一下可能的方案:
- 单步执行
这是最直接也是最浪费时间的方法,虽然你总能找到那个返回点,但显然,程序员是不会这么做的。 - 搜索并打断点
搜索函数中所有的"return"点,并在每一处设断点。这比第一点有效多了。虽然我们可以用正则表达式非常精确的定位到每一处真正的"return",但如果每次遇到这个情况都要搜一次,设一次,也比较麻烦。而且这种方法也有一点小瑕疵,假设以下代码:
1if
(a != b)
return
false
;
我们会在这一行设上断点,执行时也会break进去,但这不一定是真正的返回点。
- 重定义return关键字
1#define return TRACE(__LINE__); return;
如果我们的代码内建了这种机制,我只要看一下输出窗口的打印出的行号,就知道在哪里返回了。但是不能处理这个情况:1if
(bOK)
return
true
;
- 自定义宏替换return
1#defineRETURN(value) {TRACE(__LINE__); return value;}
的确,这是能工作的,但这要求我们修改所有现存的代码,更糟的是,以后编程也需要使用这个RETURN,让这个丑陋的RETURN成为guideline,我想大家都不愿意。
- 返回时构造
12struct
ReturnType{ ReturnType(
bool
){ } };
ReturnType LongFunction();
我们把LongFunction的返回类型改为ReturnType类,这个类的构造函数以返回类型为参数。这样,LongFunction返回时就会构造ReturnType,我们只要在其构造函数中设断点,在callstack中就能看到LongFunction是在哪里返回的。有的朋友可能会觉得这样对于不同的返回类型,就要写不同的构造函数,我们可以有两种方法来解决这个问题:
这个方案的真正问题在于要求我们修改函数返回参数,这种接口的改动影响太大。1234567// 1. 变参
struct
ReturnType{ ReturnType(...){ } };
// 2. 模板构造函数
struct
ReturnType
{
template
<
typename
T > ReturnType(T t){}
};
- 返回时析构
在资源管理中我们经常会用这种方式(RAII),现在我们利用函数返回时会调用析构函数这个特性,在析构函数中设断点,就能在callstack中看到返回点。这还有一个优点就是在LongFunction调用过程中如果出现异常,也能被捕捉。12345678class
ReturnMonitor
{
~ReturnMonitor(){}
};
bool
LongFunction()<br> {
ReturnMonitor mon;
// Function body
}
根据以上分析,我认为有两个方案只要稍加修饰,就能成为比较不错的候选方案:
第一个是"搜素并打断点",我们可以利用IDE的集成功能自动化这个步骤,比如说在Visual Studio中,我们可以写一个宏,或者写个插件来做这件事件,只要选中函数一点按钮,所有"return"自动打上断点。
第二个是"返回时析构",我们可以定义以下宏:
1 2 3 4 5 | #ifdef _DEBUG #define RETURN_MONITOR ReturnMonitor mon; #else #define RETURN_MONITOR #endif |
这样对于我们代码中比较长的,较难调试的长函数,就可以在函数开始加上RETURN_MONITOR,并且不影响release版本。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· [AI/GPT/综述] AI Agent的设计模式综述