В чем разница между __PRETTY_FUNCTION__
, __FUNCTION__
, __func__
и где они зарегистрированы? Как мне решить, какой использовать?
В чем разница между __PRETTY_FUNCTION__
, __FUNCTION__
, __func__
и где они зарегистрированы? Как мне решить, какой использовать?
Ответы:
__func__
является неявно объявленным идентификатором, который расширяется до переменной массива символов, содержащей имя функции, когда он используется внутри функции. Он был добавлен в C в C99. От C99 §6.4.2.2 / 1:
Идентификатор
__func__
неявно объявляется транслятором, как если бы, сразу после открывающей скобки каждого определения функции, объявлениеstatic const char __func__[] = "function-name";
где имя-функции - это имя лексической функции. Это имя является неукрашенным именем функции.
Обратите внимание, что это не макрос, и он не имеет особого значения во время предварительной обработки.
__func__
был добавлен в C ++ в C ++ 11, где он указан как содержащий «строку, определяемую реализацией» (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 ++ включены в документацию MSDN «Предопределенных макросов» компилятора C ++ . Расширения документации gcc описаны на странице документации gcc «Имена функций в виде строк».
__FUNCTION__
, они делают немного разные вещи. GCC дает эквивалент __func__
. VC дает неукрашенную, но все еще украшенную версию названия. Для метода с именем "foo", gcc даст вам "foo"
, VC даст "my_namespace::my_class::foo"
.
__PRETTY_FUNCTION__
он отображается в списке как доступный, и когда я наведу на него курсор мыши, он отображает информацию о названии функции, но не компилируется.
Несмотря на то, что он не полностью ответил на первоначальный вопрос, это, вероятно, то, что большинство людей, гуглявших, хотели увидеть.
Для 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**)
__func__
он, когда он встроен в другую функцию? Допустим, у меня есть function1, она не принимает аргументов. function1 вызывает function2, которая включает __func__
, какое имя функции будет напечатано, 1 или 2?
__func__
это макрос, он будет транслироваться в любую функцию, в которой вы сейчас находитесь. Если вы поместите его в f1 и вызовете f1 в f2, вы всегда получите f1.
__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 Returns: Если этот объект представляет позицию в теле функции, возвращает NTBS, определяемый реализацией, который должен соответствовать имени функции. В противном случае возвращает пустую строку.
где NTBS означает «строка байтов, завершенная нулем».
Я попробую, когда поддержка придет в 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 ++?
__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__
такой же, как __func__
в C, но в C ++ он также содержит сигнатуру типа.
__func__
не является частью C ++ 03. Он был добавлен в C ++ 0x, но C ++ 0x еще не является «стандартом C ++», он все еще находится в черновом варианте.
Для тех, кто интересуется, как это происходит в 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 main (void) из A :: f (): А <ИНТ, поплавок> :: е е void __cdecl A <int, float> :: f <bool> (void)
Использование __PRETTY_FUNCTION__
триггеров необъявленной ошибки идентификатора, как и ожидалось.