【问题标题】:What's the difference between __PRETTY_FUNCTION__, __FUNCTION__, __func__?__PRETTY_FUNCTION__、__FUNCTION__、__func__ 有什么区别?
【发布时间】:2011-05-22 01:11:49
【问题描述】:

__PRETTY_FUNCTION____FUNCTION____func__ 之间有什么区别,它们记录在哪里?我如何决定使用哪一个?

【问题讨论】:

    标签: c++ c compiler-construction standards


    【解决方案1】:

    __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__,并且只在你使用不支持它的编译器时才使用__FUNCTION__(例如,Visual C++,它不支持C99并且还不支持所有C ++0x,不提供__func__)。

    __PRETTY_FUNCTION__ 是一个 gcc 扩展,与 __FUNCTION__ 基本相同,除了对于 C++ 函数,它包含函数的“漂亮”名称,包括函数的签名。 Visual C++ 有一个类似(但不完全相同)的扩展,__FUNCSIG__

    对于非标准宏,您需要查阅编译器的文档。 Visual C++ 扩展包含在 C++ 编译器 "Predefined Macros" 的 MSDN 文档中。 gcc 文档扩展在 gcc 文档页面 "Function Names as Strings."

    中进行了描述

    【讨论】:

    • 您能否链接到 C99 规范(您的源代码中有一个浮动链接),看起来像是获胜的答案?
    • @legends2k:不,它是 C++11 中的“实现定义的字符串”。这是规范中的实际语言。见§8.4.1[dcl.fct.def.general]/8。
    • 请注意,虽然 gcc 和 VC 都提供__FUNCTION__,但它们做的事情略有不同。 gcc 相当于__func__。 VC 给出了未经修饰但仍然经过修饰的名称版本。对于名为“foo”的方法,gcc 会给出"foo",VC 会给出"my_namespace::my_class::foo"
    • 奇怪的是我使用的是 MSVC 2017 CE,当我输入 __PRETTY_FUNCTION__ 时,它确实在列表中显示为可用,当我将鼠标移到它上面时,它确实显示有关函数名,但是编译失败。
    • @FrancisCugler 我也对此感到惊讶!请参阅我的问题stackoverflow.com/questions/48857887/…
    【解决方案2】:

    尽管没有完全回答最初的问题,但这可能是大多数谷歌搜索的人希望看到的。

    对于 GCC:

    $ cat test.cpp 
    #include <iostream>
    
    int main(int argc, char **argv)
    {
        std::cout << __func__ << std::endl
                  << __FUNCTION__ << std::endl
                  << __PRETTY_FUNCTION__ << std::endl;
    }
    $ g++ test.cpp 
    $ ./a.out 
    main
    main
    int main(int, char**)
    

    【讨论】:

    • clang 3.5 的相同输出
    • 好的,但是当__func__ 嵌入到另一个函数中时它可以工作吗?可以说我有function1,它不需要参数。 function1调用包含__func__的function2,会打印哪个函数名,1还是2?
    • @MarcusJ 为什么不自己尝试一下...__func__ 是一个宏,它将转换为您当前所在的任何函数。如果您将其放入 f1 并在 f2 中调用 f1,您总是会得到 f1。
    • 我本来打算去的,然后想我会问。我觉得这行不通,而且有点让人头疼,所以我就保持原样。
    • @Petr 严格来说__func__ 是预定义标识符,而不是宏。
    【解决方案3】:

    __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__            " << __func__ << std::endl
                              << "__FUNCTION__        " << __FUNCTION__ << std::endl
                              << "__PRETTY_FUNCTION__ " << __PRETTY_FUNCTION__ << std::endl;
                }
                template <class T>
                static void f(double f) {
                    (void)f;
                    std::cout << "__PRETTY_FUNCTION__ " << __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
    

    输出:

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

    您可能还对带有函数名称的堆栈跟踪感兴趣:print call stack in C or 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 表示“空终止字节字符串”。

    该功能存在于 GCC 11.2 Ubuntu 21.10 上,-std=c++20g++-9 -std=c++2a 不在 GCC 9.1.0 上。

    https://en.cppreference.com/w/cpp/utility/source_location 显示用法是:

    main.cpp

    #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!");
    }
    

    编译运行:

    g++ -std=c++20 -Wall -Wextra -pedantic -o main.out main.cpp
    ./main.out
    

    输出:

    info:main.cpp:17:int main() Hello world!
    

    所以请注意它如何返回调用者信息,因此非常适合用于日志记录,另请参阅:Is there a way to get function name inside a C++ function?

    【讨论】:

      【解决方案4】:

      __func__ 记录在 C++0x 标准的第 8.4.1 节中。在这种情况下,它是一个预定义的函数局部变量,形式为:

      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++ 中它也包含类型签名。

      【讨论】:

      • __func__ 不是 C++03 的一部分。它已在 C++0x 中添加,但 C++0x 还不是“C++ 标准”,它仍处于草案形式。
      • @JamesMcNellis 现在是,清除 cmets 以消除噪音
      【解决方案5】:

      对于那些想知道它在 VS 中如何进行的人。

      MSVC 2015 更新 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>();
      }
      

      输出:

      从主(): 主要的 主要的 int __cdecl 主要(无效) 来自 A::f(): A::f F void __cdecl A::f&ltbool>(void)

      使用__PRETTY_FUNCTION__ 会触发未声明的标识符错误,正如预期的那样。

      【讨论】:

        猜你喜欢
        • 2015-10-04
        • 1970-01-01
        • 2014-06-07
        • 1970-01-01
        • 2016-10-31
        • 1970-01-01
        • 2011-01-17
        • 2016-12-01
        • 2012-05-01
        相关资源
        最近更新 更多