Was ist der Unterschied zwischen __PRETTY_FUNCTION__
, __FUNCTION__
, __func__
und wo sind sie dokumentiert? Wie entscheide ich mich für eine?
Was ist der Unterschied zwischen __PRETTY_FUNCTION__
, __FUNCTION__
, __func__
und wo sind sie dokumentiert? Wie entscheide ich mich für eine?
Antworten:
__func__
ist ein implizit deklarierter Bezeichner, der zu einer Zeichenarrayvariablen erweitert wird, die den Funktionsnamen enthält, wenn er innerhalb einer Funktion verwendet wird. Es wurde in C99 zu C hinzugefügt. Ab C99 §6.4.2.2 / 1:
Der Bezeichner
__func__
wird vom Übersetzer implizit deklariert, als ob unmittelbar nach der öffnenden Klammer jeder Funktionsdefinition die Deklarationstatic const char __func__[] = "function-name";
erschien, wobei Funktionsname der Name der lexikalisch einschließenden Funktion ist. Dieser Name ist der schmucklose Name der Funktion.
Beachten Sie, dass es sich nicht um ein Makro handelt und dass es während der Vorverarbeitung keine besondere Bedeutung hat.
__func__
wurde zu C ++ in C ++ 11 hinzugefügt, wo angegeben wird, dass es "eine implementierungsdefinierte Zeichenfolge" enthält (C ++ 11 §8.4.1 [dcl.fct.def.general] / 8), was nicht ganz so ist nützlich als Spezifikation in C. (Der ursprüngliche Vorschlag __func__
, C ++ hinzuzufügen , war N1642 ).
__FUNCTION__
ist eine vorstandardisierte Erweiterung, die einige C-Compiler unterstützen (einschließlich gcc und Visual C ++); im Allgemeinen sollten Sie verwenden__func__
wo es unterstützt wird, und nur verwenden, __FUNCTION__
wenn Sie einen Compiler verwenden, der es nicht unterstützt (z. B. Visual C ++, das C99 nicht unterstützt und noch nicht alles von C ++ 0x unterstützt, nicht zur Verfügung stellen __func__
).
__PRETTY_FUNCTION__
ist eine gcc-Erweiterung, die größtenteils dieselbe ist wie __FUNCTION__
, außer dass sie für C ++ - Funktionen den "hübschen" Namen der Funktion einschließlich der Signatur der Funktion enthält. Visual C ++ hat eine ähnliche (aber nicht ganz identische) Erweiterung __FUNCSIG__
.
Informationen zu nicht standardmäßigen Makros finden Sie in der Dokumentation Ihres Compilers. Die Visual C ++ - Erweiterungen sind in der MSDN-Dokumentation der "Vordefinierten Makros" des C ++ - Compilers enthalten . Die gcc-Dokumentationserweiterungen werden auf der gcc-Dokumentationsseite "Funktionsnamen als Zeichenfolgen" beschrieben.
__FUNCTION__
zwar etwas bieten , jedoch leicht unterschiedliche Aufgaben ausführen . gcc ergibt das Äquivalent von __func__
. VC gibt die nicht dekorierte, aber immer noch geschmückte Version des Namens an. Für eine Methode namens "foo" gibt gcc Ihnen "foo"
, VC gibt "my_namespace::my_class::foo"
.
__PRETTY_FUNCTION__
es in der Liste als verfügbar angezeigt. Wenn ich mit der Maus darüber fahre , werden Informationen zum Funktionsnamen angezeigt, die jedoch nicht kompiliert werden können.
Obwohl die ursprüngliche Frage nicht vollständig beantwortet wurde, ist dies wahrscheinlich das, was die meisten Leute, die googeln, sehen wollten.
Für 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__
, wenn es in eine andere Funktion eingebettet ist? Nehmen wir an, ich habe Funktion1, es werden keine Argumente benötigt. Funktion1 ruft Funktion2 auf, die enthält __func__
, welcher Funktionsname wird gedruckt, 1 oder 2?
__func__
ist ein Makro, es wird in jede Funktion übersetzt, in der Sie sich gerade befinden. Wenn Sie es in f1 setzen und f1 in f2 aufrufen, erhalten Sie immer f1.
__PRETTY_FUNCTION__
behandelt C ++ - Funktionen: Klassen, Namespaces, Vorlagen und Überladung
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);
}
Kompilieren und ausführen:
g++ -ggdb3 -O0 -std=c++11 -Wall -Wextra -pedantic -o main.out main.cpp
./main.out
Ausgabe:
f
f
static void N::C::f(int) [with T = char]
static void N::C::f(double) [with T = void]
Möglicherweise interessieren Sie sich auch für Stack-Traces mit Funktionsnamen: print call stack in C oder C ++
Getestet in 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 wurde in C ++ 20 integriert, sodass wir noch eine andere Möglichkeit haben.
Die Dokumentation sagt:
constexpr const char * Funktionsname () const noexcept;
6 Rückgabe: Wenn dieses Objekt eine Position im Hauptteil einer Funktion darstellt, wird ein implementierungsdefiniertes NTBS zurückgegeben, das dem Funktionsnamen entsprechen sollte. Andernfalls wird eine leere Zeichenfolge zurückgegeben.
Dabei bedeutet NTBS "Null Terminated Byte String".
Ich werde es versuchen, wenn der Support bei GCC eintrifft. GCC 9.1.0 g++-9 -std=c++2a
unterstützt ihn immer noch nicht.
https://en.cppreference.com/w/cpp/utility/source_location Die Nutzung von Ansprüchen lautet wie folgt:
#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!");
}
Mögliche Ausgabe:
info:main.cpp:16:main Hello world!
Beachten Sie daher, wie dies die Anruferinformationen zurückgibt und sich daher perfekt für die Protokollierung eignet. Siehe auch: Gibt es eine Möglichkeit, den Funktionsnamen in einer C ++ - Funktion abzurufen?
__func__
ist im C ++ 0x-Standard in Abschnitt 8.4.1 dokumentiert. In diesem Fall handelt es sich um eine vordefinierte lokale Funktionsvariable des Formulars:
static const char __func__[] = "function-name ";
Dabei ist "Funktionsname" implementierungsspezifisch. Dies bedeutet, dass der Compiler diese Variable implizit zu Ihrer Funktion hinzufügt, wenn Sie eine Funktion deklarieren. Gleiches gilt für __FUNCTION__
und __PRETTY_FUNCTION__
. Trotz ihrer Großbuchstaben sind sie keine Makros. Obwohl __func__
ist eine Ergänzung zu C ++ 0x
g++ -std=c++98 ....
kompiliert weiterhin Code mit __func__
.
__PRETTY_FUNCTION__
und __FUNCTION__
sind hier dokumentiert http://gcc.gnu.org/onlinedocs/gcc-4.5.1/gcc/Function-Names.html#Function-Names . __FUNCTION__
ist nur ein anderer Name für __func__
. __PRETTY_FUNCTION__
ist dasselbe wie __func__
in C, enthält jedoch in C ++ auch die Typensignatur.
__func__
ist nicht Teil von C ++ 03. Es wurde in C ++ 0x hinzugefügt, aber C ++ 0x ist noch nicht "der C ++ - Standard", es liegt noch in Entwurfsform vor.
Für diejenigen, die sich fragen, wie es in VS geht.
MSVC 2015 Update 1, cl.exe Version 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>();
}
Ausgabe:
von main (): Main Main int __cdecl main (void) von A :: f (): A <int, float> :: f f void __cdecl A <int, float> :: f <bool> (void)
Die Verwendung von __PRETTY_FUNCTION__
Triggern führt erwartungsgemäß zu einem nicht deklarierten Bezeichnerfehler.