web-dev-qa-db-ja.com

実行時に現在の関数の名前を見つける方法は?

醜いMFC ASSERTマクロを何年も使用した後、私はようやくそれを捨てて、究極のASSERTマクロを作成することにしました。

ファイルと行番号、さらには失敗した式を取得しても問題ありません。これらが入ったメッセージボックスと、中止/再試行/キャンセルボタンを表示できます。

そして、[再試行]を押すと、VSデバッガーはASSERT呼び出しを含む行にジャンプします(逆アセンブルが他のASSERT関数のような場所にあるのとは対照的です)。ですから、ほとんど問題なく動いています。

しかし、本当にクールなのは、失敗した関数の名前を表示することです

次に、ファイル名からどの関数が含まれているかを推測することなく、デバッグするかどうかを決定できます。

例えば次の機能がある場合:

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
   ASSERT(lpCreateStruct->cx > 0);
   ...
}

次に、ASSERTが起動すると、メッセージボックスは次のように表示されます。

Function = CMainFrame::OnCreate

つまり、実行時に現在の関数名を見つける最も簡単な方法は何ですか?

MFCも.NET Frameworkも使用しないでください。両方を使用しています。
可能な限り移植可能である必要があります。

36
demoncodemonkey

マクロには__FUNCTION__マクロを含めることができます。間違いなく、関数名されるは拡張コードにコンパイル時に挿入されますが、マクロへの呼び出しごとに正しい関数名になります。したがって、実行時に発生するように見えます;)

例えば.

#define THROW_IF(val) if (val) throw "error in " __FUNCTION__

int foo()
{
    int a = 0;
    THROW_IF(a > 0); // will throw "error in foo()"
}
52
Assaf Lavie

C++プリプロセッサマクロ__FUNCTION__は、関数の名前を示します。

これを使用すると、実行時にファイル名、行番号、または関数名を取得するreallyではないことに注意してください。マクロはプリプロセッサによって展開され、コンパイルされます。

__FUNCTION__マクロは、__LINE____FILE__と同様に、言語標準の一部であり、移植可能です。

プログラム例:

#include <iostream>
#using namespace std;

void function1()
{
        cout << "my function name is: " << __FUNCTION__ << "\n";
}
int main()
{
        cout << "my function name is: " << __FUNCTION__ << "\n";
        function1();
        return 0;
}

出力:

私の関数名は:main 
私の関数名は:function1 
23
YenTheFirst

標準的な解決策はありません。しかしながら、 - BOOST_CURRENT_FUNCTION は、あらゆる実用的な目的で移植可能です。ヘッダーは他のBoostヘッダーに依存しないため、ライブラリ全体のオーバーヘッドが許容できない場合はスタンドアロンで使用できます。

18
fizzer
10
DaClown

GCCでは、__PRETTY_FUNCTION__マクロを使用できます。
Microsoftには同等の__func__マクロもありますが、試すことはできません。

例えば__PRETTY_FUNCTION__を使用するには、関数の先頭にこのようなものを配置すると、完全なトレースが得られます

void foo(char* bar){
  cout << __PRETTY_FUNCTION__ << std::endl
}

出力されます

void foo(char* bar)

さらに多くの情報を出力したい場合は、__FILE__および__LINE__マクロをすべての標準c/c ++コンパイラーで使用できます。

実際には、coutの代わりに使用する特別なデバッグクラスがあります。適切な環境変数を定義することで、完全なプログラムトレースを取得できます。同様のことができます。これらのマクロは非常に便利であり、このような選択的なデバッグをフィールドでオンにできることは本当に素晴らしいことです。

編集:明らかに__func__は標準の一部ですか?知らなかった。残念ながら、これは関数名のみを提供し、パラメーターも提供しません。私はgccの__PRETTY_FUNC__が好きですが、他のコンパイラに移植することはできません。

GCCは__FUNCTION__もサポートしています。

8
Matt

__FUNCTION__マクロ コンパイル時に関数の名前に展開されます。

これは、assertマクロで使用する方法の例です。

#define ASSERT(cond) \
    do { if (!(cond)) \
    MessageBoxFunction("Failed: %s in Function %s", #cond, __FUNCTION__);\
    } while(0)

void MessageBoxFunction(const char* const msg,  ...)
{
    char szAssertMsg[2048];

    // format args
    va_list vargs;
    va_start(vargs, msg);
    vsprintf(szAssertMsg, msg, vargs);
    va_end(vargs);

    ::MessageBoxA(NULL, szAssertMsg, "Failed Assertion", MB_ICONERROR | MB_OK);
}
5
Andrew Grant

funcを簡単に使用できます。実行時に例外を発生させた現在の関数名を取り戻します。

使用法:

cout << __func__ << ": " << e.what();
0
Hosein Basafa