В чем разница между __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<bool>(void)
Использование __PRETTY_FUNCTION__
запускает необъявленную ошибку идентификатора, как и ожидалось.