Какая разница между __PRETTY_FUNCTION__, __FUNCTION__, __func__?

В чем разница между __PRETTY_FUNCTION__, __FUNCTION__, __func__ и где они задокументированы? Как я могу решить, какой из них использовать?

Ответ 1

__func__ - это неявно объявленный идентификатор, который расширяется до переменной массива символов, содержащей имя функции, когда она используется внутри функции. Он был добавлен в C на C99. Из C99 §6.4.2.2/1:

Идентификатор __func__ неявно объявляется переводчиком, как если бы, сразу после открытия скобки каждого определения функции, объявление

static const char __func__[] = "function-name";
Появился

где function-name - имя лексически-охватывающей функции. Это имя является неотъемлемым именем функции.

Обратите внимание, что это не макрос, и он не имеет особого значения во время предварительной обработки.

__func__ был добавлен в С++ в С++ 11, где он указан как содержащий "строку, определяемую реализацией" (С++ 11 §8.4.1 [dcl.fct.def.general]/8), что не так полезно, как спецификация в C. (Исходное предложение добавить __func__ в С++ было N1642).

__FUNCTION__ является предварительным стандартным расширением, поддерживаемым некоторыми компиляторами C (включая gcc и Visual С++); в общем случае вы должны использовать __func__, где он поддерживается, и использовать только __FUNCTION__, если вы используете компилятор, который его не поддерживает (например, Visual С++, который не поддерживает C99 и еще не поддерживает все С++ 0x, не предоставляет __func__).

__PRETTY_FUNCTION__ - это расширение gcc, которое в основном совпадает с __FUNCTION__, за исключением того, что для функций С++ оно содержит "красивое" имя функции, включая подпись функции. Visual С++ имеет аналогичное (но не совсем идентичное) расширение, __FUNCSIG__.

Для нестандартных макросов вы захотите ознакомиться с документацией вашего компилятора. Расширения Visual С++ включены в документацию MSDN компилятора С++ "Предопределенные макросы" . Расширения документации gcc описаны на странице документации gcc Имена функций как строки.

Ответ 2

Несмотря на то, что он не полностью ответил на первоначальный вопрос, вероятно, именно это и хотелось увидеть большинству людей, гуглящих на этом.

Для GCC:

[email protected]:~$ cat test.cpp 
#include <iostream>

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

Ответ 3

__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++

Ответ 4

__func__ документируется в стандарте С++ 0x в разделе 8.4.1. В этом случае это предопределенная локальная переменная функции вида:

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

где "имя функции" - это реализация specfic. Это означает, что всякий раз, когда вы объявляете функцию, компилятор неявно добавляет эту переменную в вашу функцию. То же самое относится к __FUNCTION__ и __PRETTY_FUNCTION__. Несмотря на их верхнюю строчку, они не являются макросами. Хотя __func__ является дополнением к С++ 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__ совпадает с __func__ в C, но в С++ он также содержит подпись типа.

Ответ 5

Для тех, кто задается вопросом, как это происходит в 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__ запускает необъявленную ошибку идентификатора, как и ожидалось.