У чому різниця між __PRETTY_FUNCTION__, __FUNCTION__, __func__і де вони зареєстровані? Як вирішити, який з них використовувати?
У чому різниця між __PRETTY_FUNCTION__, __FUNCTION__, __func__і де вони зареєстровані? Як вирішити, який з них використовувати?
Відповіді:
__func__це неявно оголошений ідентифікатор, який розширюється до змінної масиву символів, що містить ім'я функції, коли він використовується всередині функції. Він був доданий до C у C99. З C99 § 6.4.2.2 / 1:
__func__Перекладач неявно оголошує ідентифікатор так, ніби одразу слідуючи за діаграмою відкриття кожного визначення функції, декларацієюstatic const char __func__[] = "function-name";з'явилося, де 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__працює, коли він вбудований в іншу функцію? Скажімо, у мене функція1, вона не бере аргументів. function1 викликає функцію2, яка включає __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 Повернення: Якщо цей об'єкт представляє позицію в тілі функції, повертає визначену реалізацією 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 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>();
}
вихід:
з головного (): головний головний int __cdecl main (недійсний) від A :: f (): A <int, float> :: f f void __cdecl A <int, float> :: f <bool> (void)
Використання __PRETTY_FUNCTION__тригерів недекларованої помилки ідентифікатора, як очікувалося.