__PRETTY_FUNCTION __、__ FUNCTION __、__ func__の違いは何ですか?


回答:


266

__func__関数内で使用すると、関数名を含む文字配列変数に展開される暗黙的に宣言された識別子です。C99でCに追加されました。C99 / 1§6.4.2.2:

識別子__func__は、各関数定義の左中括弧の直後に、宣言が

static const char __func__[] = "function-name";

ここでfunction-nameは、字句的に囲む関数の名前です。この名前は、関数の装飾されていない名前です。

これはマクロではなく、前処理中に特別な意味はないことに注意してください。

__func__C ++ 11のC ++に追加されました。「実装定義の文字列」(C ++ 11§8.4.1[dcl.fct.def.general] / 8)を含むものとして指定されています。 Cの仕様として役立ちます(__func__C ++に追加する最初の提案はN1642でした)。

__FUNCTION__一部のCコンパイラがサポートする先行標準の拡張機能です(gccおよびVisual C ++を含む)。一般に、__func__それがサポートされている場所で使用し、それをサポートし__FUNCTION__ていないコンパイラーを使用している場合にのみ使用してください(例えば、Visual C ++は、C99をサポートせず、まだすべてのC ++ 0xをサポートしていません。提供する__func__)。

__PRETTY_FUNCTION____FUNCTION__C ++関数の場合、関数のシグネチャを含む関数の「かなり」の名前が含まれていることを除いて、とほぼ同じgcc拡張です。Visual C ++にも同様の(ただし完全に同一ではない)拡張子があり__FUNCSIG__ます。

非標準のマクロについては、コンパイラのドキュメントを参照してください。Visual C ++拡張機能は、C ++コンパイラの「事前定義マクロ」のMSDNドキュメントに含まれています。gccドキュメンテーション拡張機能は、gccドキュメンテーションページの「文字列としての関数名」で説明されています


C99仕様にリンクできますか(ソースにフローティングリンクがあります)。
マットジョイナー

1
@ legends2k:いいえ、C ++ 11では「実装定義の文字列」です。それが仕様の実際の言語です。§8.4.1[dcl.fct.def.general] / 8を参照してください。
James McNellis 2013年

2
gccとVCはどちらもを提供しますが__FUNCTION__、動作が少し異なることに注意してください。gccはと同等のものを提供し__func__ます。VCは、装飾されていないがまだ装飾されたバージョンの名前を提供します。「foo」という名前のメソッドの場合"foo"、gccは、VCはを提供し"my_namespace::my_class::foo"ます。
エイドリアンマッカーシー

1
不思議なのは、MSVC 2017 CEを使用し__PRETTY_FUNCTION__ていて、入力するとリストに表示され、利用可能であると表示され、マウスをその上に移動すると、関数名に関する情報が表示されますが、コンパイルに失敗します。
Francis Cugler 2017

1
@FrancisCugler私もこれでびっくりしました!私の質問をご覧ください。stackoverflow.com
アダムバドゥラ

108

元の質問に完全には答えていませんが、これはおそらくこれをググる人のほとんどが見たかったことです。

GCCの場合:

petanb@debian:~$ cat test.cpp 
#include <iostream>

int main(int argc, char **argv)
{
    std::cout << __func__ << std::endl
              << __FUNCTION__ << std::endl
              << __PRETTY_FUNCTION__ << std::endl;
}
petanb@debian:~$ g++ test.cpp 
petanb@debian:~$ 
petanb@debian:~$ ./a.out 
main
main
int main(int, char**)

6
私はこれが適切な答えではないことを知っていますが、これはおそらくこれをグーグルで見たいと思っていたほとんどの人です:)(彼らが自分で試すのが面倒な場合)
Petr

5
公正な呼び方、これは見るのにうれしい。
Matt Joiner 2014年

13
clang 3.5からの同じ出力
Doncho Gunchev 2014

わかりましたが__func__、別の関数に埋め込まれている場合は機能しますか?function1があるとしましょう。引数はありません。function1はを含むfunction2を呼び出し__func__ます。印刷される関数名は1または2ですか。
MarcusJ 2017年

@MarcusJ自分で試してみてください...これ__func__はマクロです。現在ある関数に変換されます。それをf1に入れ、f2でf1を呼び出すと、常にf1を取得します。
Petr

41

__PRETTY_FUNCTION__ C ++機能を処理します:クラス、名前空間、テンプレート、オーバーロード

main.cpp

#include <iostream>

namespace N {
    class C {
        public:
            template <class T>
            static void f(int i) {
                (void)i;
                std::cout << __func__ << std::endl
                          << __FUNCTION__ << std::endl
                          << __PRETTY_FUNCTION__ << std::endl;
            }
            template <class T>
            static void f(double f) {
                (void)f;
                std::cout << __PRETTY_FUNCTION__ << std::endl;
            }
    };
}

int main() {
    N::C::f<char>(1);
    N::C::f<void>(1.0);
}

コンパイルして実行します。

g++ -ggdb3 -O0 -std=c++11 -Wall -Wextra -pedantic -o main.out main.cpp
./main.out

出力:

f
f
static void N::C::f(int) [with T = char]
static void N::C::f(double) [with T = void]

関数名の付いたスタックトレースにも興味があるかもしれません:CまたはC ++でのコールスタックの印刷

Ubuntu 19.04、GCC 8.3.0でテスト済み。

C ++ 20 std::source_location::function_name

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1208r5.pdfがC ++ 20に入ったので、それを行う別の方法があります。

ドキュメントは言う:

constexpr const char * function_name()const noexcept;

6戻り値:このオブジェクトが関数の本体の位置を表す場合、関数名に対応する実装定義のNTBSを返します。それ以外の場合は、空の文字列を返します。

ここで、NTBSは「Null Terminated Byte String」を意味します。

サポートがGCCに届いたら、GCC 9.1.0 g++-9 -std=c++2aがまだサポートされていないときに試してみます。

https://en.cppreference.com/w/cpp/utility/source_locationの使用法は次のようになります。

#include <iostream>
#include <string_view>
#include <source_location>

void log(std::string_view message,
         const std::source_location& location std::source_location::current()
) {
    std::cout << "info:"
              << location.file_name() << ":"
              << location.line() << ":"
              << location.function_name() << " "
              << message << '\n';
}

int main() {
    log("Hello world!");
}

可能な出力:

info:main.cpp:16:main Hello world!

これが呼び出し元の情報を返す方法に注意してください。したがって、ロギングでの使用に最適です。C++関数内の関数名を取得する方法はありますか。


13

__func__セクション8.4.1のC ++ 0x標準に文書化されています。この場合は、次の形式の事前定義された関数ローカル変数です。

static const char __func__[] = "function-name ";

ここで、「関数名」は実装固有です。つまり、関数を宣言すると、コンパイラーはこの変数を暗黙的に関数に追加します。同じことが真のである__FUNCTION____PRETTY_FUNCTION__。それらが大文字であるにもかかわらず、それらはマクロではありません。が__func__C ++ 0xのに加えています

g++ -std=c++98 ....

は引き続きを使用してコードをコンパイルします__func__

__PRETTY_FUNCTION__そして__FUNCTION__ここに記述されていhttp://gcc.gnu.org/onlinedocs/gcc-4.5.1/gcc/Function-Names.html#Function-Names__FUNCTION__はの別名です__func__。C __PRETTY_FUNCTION__と同じです__func__が、C ++では型シグネチャも含まれています。


__func__C ++ 03の一部ではありません。C ++ 0xで追加されましたが、C ++ 0xはまだ「C ++標準」ではなく、まだドラフト形式です。
James McNellis、2010

2
@JamesMcNellisノイズを取り除くために、コメントをクリアしました
daramarak

7

それがVSでどうなるのか疑問に思う人のために。

MSVC 2015 Update 1、cl.exeバージョン19.00.24215.1:

#include <iostream>

template<typename X, typename Y>
struct A
{
  template<typename Z>
  static void f()
  {
    std::cout << "from A::f():" << std::endl
      << __FUNCTION__ << std::endl
      << __func__ << std::endl
      << __FUNCSIG__ << std::endl;
  }
};

void main()
{
  std::cout << "from main():" << std::endl
    << __FUNCTION__ << std::endl
    << __func__ << std::endl
    << __FUNCSIG__ << std::endl << std::endl;

  A<int, float>::f<bool>();
}

出力:

main()から:
メイン
メイン
int __cdecl main(void)

A :: f()から:
A <int、float> :: f
f
void __cdecl A <int、float> :: f <bool>(void)

__PRETTY_FUNCTION__トリガーを使用すると、予想どおり、未宣言の識別子エラーが発生します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.