Was ist der Unterschied zwischen __PRETTY_FUNCTION__, __FUNCTION__, __func__?

221

Was ist der Unterschied zwischen __PRETTY_FUNCTION__, __FUNCTION__, __func__und wo sind sie dokumentiert? Wie entscheide ich mich für eine?

Matt Joiner
quelle

Antworten:

266

__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 Deklaration

static 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.

James McNellis
quelle
Können Sie einen Link zur C99-Spezifikation erstellen (in Ihrer Quelle befindet sich ein schwebender Link), um zu erfahren, wie die Gewinnerantwort aussieht?
Matt Joiner
1
@ legends2k: Nein, es ist "eine implementierungsdefinierte Zeichenfolge" in C ++ 11. Das ist die eigentliche Sprache aus der Spezifikation. Siehe §8.4.1 [dcl.fct.def.general] / 8.
James McNellis
2
Beachten Sie, dass sowohl gcc als auch VC __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".
Adrian McCarthy
1
Was merkwürdig ist, ist, dass ich MSVC 2017 CE verwende. Wenn ich tippe, wird __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.
Francis Cugler
1
@FrancisCugler Das hat mich auch überrascht! Siehe meine Frage darauf stackoverflow.com/questions/48857887/…
Adam Badura
108

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**)
Petr
quelle
6
Ich weiß, dass dies keine richtige Antwort ist, aber es ist wahrscheinlich das, was fast jeder, der dies googelt, sehen wollte :) (wenn er faul ist, es selbst zu versuchen)
Petr
5
Fairer Anruf, das ist schön zu sehen.
Matt Joiner
13
Gleiche Ausgabe von Clang 3.5
Doncho Gunchev
Ok, aber funktioniert es __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?
MarcusJ
@MarcusJ warum nicht selbst ausprobieren ... das __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.
Petr
41

__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++2aunterstü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?

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
quelle
13

__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.

Sashang
quelle
__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.
James McNellis
2
@ JamesMcNellis Es ist jetzt, so klar die Kommentare, das Rauschen zu entfernen
Daramarak
7

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.

finnan
quelle