Windows では、いくつかのことで洞察を得ることができます。まず、調査したいバイナリに対応するシンボル ファイルと呼ばれるものが必要です。シンボル ファイルは、テキスト名を、プログラム内に存在するグローバル/スタック/ヒープ変数に関連付けます。したがって、メモリ内のアドレスを関数 fgets にマップし、特定のプログラムで fgets を確認するには、Microsoft の C std ライブラリの実装のバージョンのシンボルが必要です。Lucky for you MS はシンボルを自由に利用できるようにします
次に、fgets よりも深く掘り下げたコールスタックをキャプチャする必要があります。これを行う最も明白な方法は、Microsoft の開発者であり、ディープ MS dll にクラッシュを導入し、デバッガーとシンボルを使用してクラッシュ ダンプを分析することですが、残念ながらそれはできません。できることは、サンプリング プロファイラーと呼ばれるものを使用することです。たとえば、Microsoft から無料で入手できます。サンプリング プロファイラーは、プログラムのコールスタックのスナップショットを定期的に取得して、コードをプロファイリングします。Microsoft のシンボル ファイルを使用すると、そのコールスタックを意味のあるものに消化できます。
これら 2 つの情報があれば、プログラムを作成して 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
------------------------------------------------------------
プロファイラーの出力を取得します。コマンドが Microsoft のシンボル サーバーを指すように「symbolpath」スイッチがあることに注意してください。
C:\path\to\exe>vsperfreport perfplay.vsp /summary:all /symbolpath:srv*c:\symbols*htt
p://msdl.microsoft.com/download/symbols
呼び出し元と呼び出し先のレポートの csv を直接調べるか、私が取り組んできたような優れたビューアーを見つけることができます。fgets がほとんどの時間を費やしている場所を把握できます。

悲しいことに、ひどく洞察力がありません。残念ながら、このアプローチで遭遇する問題の 1 つは、リリース モードで fgets が呼び出す関数の多くがインライン化される可能性が非常に高いということです。つまり、関数は最終的なプログラムから関数としてほとんど削除され、その内容は直接 "使用する場所に貼り付けます。
インライン化の可能性が少ないため、デバッグ モードで上記を繰り返して、何が得られるかを確認できます。