web-dev-qa-db-ja.com

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

__PRETTY_FUNCTION____FUNCTION____func__の違いは何ですか?また、どこに文書化されていますか?どちらを使用するかをどのように決定しますか?

197
Matt Joiner

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

識別子__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__を使用し、それをサポートしていないコンパイラ(たとえば、C99をサポートしておらず、まだサポートしていないVisual C++)を使用する場合にのみ__FUNCTION__すべてのC++ 0xをサポートしますが、__func__)は提供しません。

__PRETTY_FUNCTION__はgcc拡張であり、ほとんどが__FUNCTION__と同じですが、C++関数の場合は、関数の署名を含む関数の「きれいな」名前が含まれます。 Visual C++には、__FUNCSIG__という同様の(完全に同一ではない)拡張機能があります。

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

240
James McNellis

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

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**)
88
Petr

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

#include <iostream>

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

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

出力GCC 7.2 g++ -std=gnu++98

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

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

C++ 20 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にサポートが届いたら試してみます。GCC9.1.0のg++-9 -std=c++2aはまだサポートしていません。

__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__の単なる別の名前です。 __PRETTY_FUNCTION__はCの__func__と同じですが、C++では型シグネチャも含まれます。

12
sashang

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>();
}

出力:

 from main():
 main 
 main 
 int __cdecl main(void)
 
 from A :: f() :
 A <int、float> :: f 
 f 
 void __cdecl A <int、float> :: f&ltbool>(void)

__PRETTY_FUNCTION__を使用すると、予想どおり、宣言されていない識別子エラーが発生します。

5
finnan