Jaka jest różnica między __PRETTY_FUNCTION__
, __FUNCTION__
, __func__
, i gdzie są one udokumentowane? Jak zdecydować, którego użyć?
Jaka jest różnica między __PRETTY_FUNCTION__
, __FUNCTION__
, __func__
, i gdzie są one udokumentowane? Jak zdecydować, którego użyć?
Odpowiedzi:
__func__
jest niejawnie zadeklarowanym identyfikatorem, który rozwija się do zmiennej tablicy znaków zawierającej nazwę funkcji, gdy jest używana wewnątrz funkcji. Został dodany do C w C99. Od C99 §6.4.2.2 / 1:
Identyfikator
__func__
jest domyślnie zadeklarowany przez tłumacza, tak jakby deklaracja znajdowała się bezpośrednio po nawiasie otwierającym każdej definicji funkcjistatic const char __func__[] = "function-name";
pojawił się, gdzie nazwa-funkcji jest nazwą funkcji zamykającej leksykalnie. Ta nazwa jest nie ozdobioną nazwą funkcji.
Należy pamiętać, że nie jest to makro i nie ma specjalnego znaczenia podczas przetwarzania wstępnego.
__func__
został dodany do C ++ w C ++ 11, gdzie jest określony jako zawierający „ciąg zdefiniowany w implementacji” (C ++ 11 §8.4.1 [dcl.fct.def.general] / 8), co nie jest tak bardzo użyteczne jako specyfikacja w C. (Oryginalna propozycja dodania __func__
do C ++ to N1642 ).
__FUNCTION__
jest standardowym rozszerzeniem obsługiwanym przez niektóre kompilatory C (w tym gcc i Visual C ++); ogólnie powinieneś używać __func__
tam, gdzie jest obsługiwany i używać tylko __FUNCTION__
wtedy, gdy używasz kompilatora, który go nie obsługuje (na przykład Visual C ++, który nie obsługuje C99 i nie obsługuje jeszcze całego C ++ 0x, nie zapewnić __func__
).
__PRETTY_FUNCTION__
jest rozszerzeniem gcc, które jest w większości takie samo __FUNCTION__
, z wyjątkiem tego, że dla funkcji C ++ zawiera „ładną” nazwę funkcji, w tym podpis funkcji. Visual C ++ ma podobne (ale nie do końca identyczne) rozszerzenie,__FUNCSIG__
.
W przypadku niestandardowych makr warto zajrzeć do dokumentacji kompilatora. Rozszerzenia Visual C ++ są zawarte w dokumentacji MSDN kompilatora C ++ „Predefiniowane makra” . Rozszerzenia dokumentacji gcc są opisane na stronie dokumentacji gcc „Nazwy funkcji jako ciągi znaków”.
__FUNCTION__
, robią nieco inne rzeczy. gcc daje równowartość __func__
. VC podaje nieudekorowaną, ale wciąż ozdobioną wersję nazwy. W przypadku metody o nazwie „foo”, gcc da ci "foo"
, VC da "my_namespace::my_class::foo"
.
__PRETTY_FUNCTION__
, pojawia się na liście jako dostępny, a kiedy na nim przesunę kursor myszy, wyświetla informacje o nazwie funkcji, jednak nie kompiluje się.
Mimo, że nie udało się w pełni odpowiedzieć na pierwotne pytanie, prawdopodobnie właśnie to chciało zobaczyć większość osób odwiedzających google.
W przypadku 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__
działa, gdy jest osadzony w innej funkcji? Powiedzmy, że mam funkcję1, nie wymaga żadnych argumentów. funkcja 1 wywołuje funkcję 2, która obejmuje __func__
, która nazwa funkcji zostanie wydrukowana, 1 czy 2?
__func__
to makro, to tłumaczy na dowolną funkcję, w której się obecnie znajdujesz. Jeśli umieścisz go w f1 i wywołasz f1 w f2, zawsze dostaniesz f1.
__PRETTY_FUNCTION__
obsługuje funkcje C ++: klasy, przestrzenie nazw, szablony i przeciążenie
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);
}
Skompiluj i uruchom:
g++ -ggdb3 -O0 -std=c++11 -Wall -Wextra -pedantic -o main.out main.cpp
./main.out
Wynik:
f
f
static void N::C::f(int) [with T = char]
static void N::C::f(double) [with T = void]
Mogą Cię również zainteresować ślady stosu z nazwami funkcji: wydrukuj stos wywołań w C lub C ++
Testowane w 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 przeszedł do C ++ 20, więc mamy jeszcze inny sposób, aby to zrobić.
Dokumentacja mówi:
constexpr const char * nazwa_funkcji () const noexcept;
6 Zwraca: Jeśli ten obiekt reprezentuje pozycję w treści funkcji, zwraca zdefiniowaną implementację NTBS, która powinna odpowiadać nazwie funkcji. W przeciwnym razie zwraca pusty ciąg.
gdzie NTBS oznacza „Ciąg bajtów zakończony zerem”.
Spróbuję, kiedy wsparcie dotrze do GCC, GCC 9.1.0 g++-9 -std=c++2a
nadal go nie obsługuje.
https://en.cppreference.com/w/cpp/utility/source_location roszczenia będą wyglądać następująco:
#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!");
}
Możliwe wyjście:
info:main.cpp:16:main Hello world!
więc zwróć uwagę, jak to zwraca informacje o dzwoniącym, a zatem idealnie nadaje się do użycia przy logowaniu, zobacz także: Czy istnieje sposób na uzyskanie nazwy funkcji wewnątrz funkcji C ++?
__func__
jest udokumentowane w standardzie C ++ 0x w sekcji 8.4.1. W tym przypadku jest to predefiniowana lokalna zmienna funkcji w formie:
static const char __func__[] = "function-name ";
gdzie „nazwa funkcji” jest specyficzna dla implementacji. Oznacza to, że za każdym razem, gdy deklarujesz funkcję, kompilator doda tę zmienną niejawnie do twojej funkcji. To samo dotyczy __FUNCTION__
i __PRETTY_FUNCTION__
. Mimo górnej części nie są makrami. Chociaż __func__
jest dodatkiem do C ++ 0x
g++ -std=c++98 ....
nadal będzie kompilować kod za pomocą __func__
.
__PRETTY_FUNCTION__
i __FUNCTION__
są udokumentowane tutaj http://gcc.gnu.org/onlinedocs/gcc-4.5.1/gcc/Function-Names.html#Function-Names . __FUNCTION__
to po prostu inna nazwa dla __func__
. __PRETTY_FUNCTION__
jest taki sam jak __func__
w C, ale w C ++ zawiera również podpis typu.
__func__
nie jest częścią C ++ 03. Został dodany w C ++ 0x, ale C ++ 0x nie jest jeszcze „standardem C ++”, ale nadal jest w wersji roboczej.
Dla tych, którzy zastanawiają się, jak to wygląda w VS.
MSVC 2015 Update 1, cl.exe wersja 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>();
}
wynik:
z main (): Główny Główny int __cdecl main (void) z A :: f (): A <int, float> :: f fa void __cdecl A <int, float> :: f <bool> (void)
Korzystanie z __PRETTY_FUNCTION__
wyzwalaczy niezadeklarowany błąd identyfikatora, zgodnie z oczekiwaniami.