在 Windows 上,您可以通过一些事情获得一些见解。首先,您需要与您要调查的二进制文件相对应的符号文件。符号文件将文本名称与程序中浮动的全局/堆栈/堆变量相关联。因此,要将内存中的地址映射到函数 fgets,并在某些程序中查看 fgets,您需要具有 Microsoft 实现的 C std 库版本的符号。幸运的是,MS 制作了他们的符号freely available
其次,您需要捕获比 fgets 更深的调用堆栈。最明显的方法是成为 Microsoft 开发人员并将崩溃引入深层 MS dll,然后使用调试器和符号分析崩溃转储,但不幸的是我们不能这样做。你可以做的是使用所谓的采样分析器,就像在this one 中免费提供的Microsoft 一样。采样分析器通过定期对程序的调用堆栈进行快照来分析您的代码。使用 Microsoft 的符号文件,我们可以将该调用堆栈消化成有意义的东西。
鉴于这两条信息,构建程序并深入了解 fgets 调用的内容并不难。然后,您可以使用带有 Microsoft 符号的采样分析器来了解您的程序期间发生了什么。
按照这些思路,我构建了以下程序来尝试一下:
int FgetSTest()
{
FILE* fp;
fp = fopen("C:/test.txt", "w");
char data[100];
int sum = 0;
for (int i = 0; i < 100; ++i)
{
fgets(data, 100, fp);
sum += data[0];
}
fclose(fp);
return sum;
}
int _tmain(int argc, _TCHAR* argv[])
{
int sum = 0;
for (int i = 0; i < 100; ++i)
{
sum += FgetSTest();
}
std::cout << sum;
return 0;
}
假设您已将其编译为一个程序(我已将其编译为一个名为 perfPlay.exe 的程序),您可以在该 exe 上运行 MS 的采样分析器,如下所示:
C:\path\to\exe>vsperfcmd /start:sample /output:perfPlay.vsp
Microsoft (R) VSPerf Command Version 9.0.30729 x86
Copyright (C) Microsoft Corp. All rights reserved.
C:\path\to\exe\>vsperfcmd /launch:perfPlay.exe
Microsoft (R) VSPerf Command Version 9.0.30729 x86
Copyright (C) Microsoft Corp. All rights reserved.
Successfully launched process ID:3700 perfPlay.exe
sum is:40000
C:\path\to\exe>vsperfcmd /shutdown
Microsoft (R) VSPerf Command Version 9.0.30729 x86
Copyright (C) Microsoft Corp. All rights reserved.
Shutting down the Profile Monitor
------------------------------------------------------------
获取分析器输出,注意“符号路径”开关将命令指向微软的符号服务器:
C:\path\to\exe>vsperfreport perfplay.vsp /summary:all /symbolpath:srv*c:\symbols*htt
p://msdl.microsoft.com/download/symbols
您可以直接检查调用者-被调用者报告的 csv,或者找到一个好的查看器,例如 the one I've been working on,您可以了解 fgets 大部分时间花在哪里:
可悲的是,并不是很有洞察力。不幸的是,使用这种方法会遇到的一个问题是,许多 fgets 在发布模式下调用的函数很可能是inlined——也就是说,它们几乎作为函数从最终程序及其内容中删除了直接“粘贴”到使用它们的位置。
您可以尝试在调试模式下重复上述操作以查看您得到的结果,因为内联的机会较小。