У чому різниця між __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__
тригерів недекларованої помилки ідентифікатора, як очікувалося.