Quelle est la différence entre __PRETTY_FUNCTION__, __FUNCTION__, __func__?

221

Quelle est la différence entre __PRETTY_FUNCTION__, __FUNCTION__, __func__et où sont - ils documentés? Comment puis-je décider lequel utiliser?

Matt Joiner
la source

Réponses:

266

__func__est un identifiant déclaré implicitement qui se développe en une variable de tableau de caractères contenant le nom de la fonction lorsqu'il est utilisé à l'intérieur d'une fonction. Il a été ajouté à C en C99. À partir de C99 §6.4.2.2 / 1:

L'identifiant __func__est implicitement déclaré par le traducteur comme si, immédiatement après l'accolade ouvrante de chaque définition de fonction, la déclaration

static const char __func__[] = "function-name";

est apparu, où nom-fonction est le nom de la fonction entourant lexicalement. Ce nom est le nom sans fioritures de la fonction.

Notez qu'il ne s'agit pas d'une macro et qu'elle n'a aucune signification particulière lors du prétraitement.

__func__a été ajouté à C ++ dans C ++ 11, où il est spécifié comme contenant "une chaîne définie par l'implémentation" (C ++ 11 §8.4.1 [dcl.fct.def.general] / 8), ce qui n'est pas tout à fait utile comme spécification en C. (La proposition originale à ajouter __func__au C ++ était N1642 ).

__FUNCTION__est une extension pré-standard prise en charge par certains compilateurs C (y compris gcc et Visual C ++); en général, vous devez utiliser __func__là où il est pris en charge et uniquement __FUNCTION__si vous utilisez un compilateur qui ne le prend pas en charge (par exemple, Visual C ++, qui ne prend pas en charge C99 et ne prend pas encore en charge la totalité de C ++ 0x, ne fournir __func__).

__PRETTY_FUNCTION__est une extension gcc qui est essentiellement la même que __FUNCTION__, sauf que pour les fonctions C ++, elle contient le "joli" nom de la fonction, y compris la signature de la fonction. Visual C ++ a une extension similaire (mais pas tout à fait identique), __FUNCSIG__.

Pour les macros non standard, vous voudrez consulter la documentation de votre compilateur. Les extensions Visual C ++ sont incluses dans la documentation MSDN des «macros prédéfinies» du compilateur C ++ . Les extensions de la documentation de gcc sont décrites dans la page de documentation de gcc "Noms de fonction en tant que chaînes".

James McNellis
la source
Pouvez-vous lier à la spécification C99 (il y a un lien flottant dans votre source), pour ce qui ressemble à la réponse gagnante?
Matt Joiner
1
@ legends2k: Non, c'est "une chaîne définie par l'implémentation" en C ++ 11. C'est la langue réelle de la spécification. Voir §8.4.1 [dcl.fct.def.general] / 8.
James McNellis
2
Notez que bien que gcc et VC fournissent __FUNCTION__, ils font des choses légèrement différentes. gcc donne l'équivalent de __func__. VC donne la version non décorée, mais toujours ornée, du nom. Pour une méthode nommée "foo", gcc vous donnera "foo", VC vous donnera "my_namespace::my_class::foo".
Adrian McCarthy
1
Ce qui est curieux, c'est que j'utilise MSVC 2017 CE et lorsque je tape, __PRETTY_FUNCTION__il apparaît dans la liste comme étant disponible et lorsque je déplace ma souris dessus, il affiche des informations sur le nom de la fonction, mais il ne parvient pas à compiler.
Francis Cugler
1
@FrancisCugler Cela m'a également surpris! Voir ma question à ce sujet stackoverflow.com/questions/48857887/…
Adam Badura
108

Bien qu'il n'ait pas pleinement répondu à la question initiale, c'est probablement ce que la plupart des gens recherchent sur Google.

Pour 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
la source
6
Je sais que ce n'est pas une bonne réponse, mais c'est probablement ce que presque tous ceux qui recherchent sur Google veulent voir :) (s'ils sont paresseux pour s'essayer)
Petr
5
Bon appel, c'est agréable à voir.
Matt Joiner
13
Même sortie de clang 3.5
Doncho Gunchev
Ok, mais ça __func__marche quand il est intégré dans une autre fonction? Disons que j'ai function1, cela ne prend aucun argument. function1 appelle function2 qui inclut __func__, quel nom de fonction sera imprimé, 1 ou 2?
MarcusJ
@MarcusJ pourquoi ne pas l'essayer vous-même ... __func__c'est une macro, elle se traduira dans la fonction dans laquelle vous vous trouvez actuellement. Si vous la mettez dans f1 et appelez f1 dans f2, vous obtiendrez toujours f1.
Petr
41

__PRETTY_FUNCTION__ gère les fonctionnalités C ++: classes, espaces de noms, modèles et surcharge

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);
}

Compiler et exécuter:

g++ -ggdb3 -O0 -std=c++11 -Wall -Wextra -pedantic -o main.out main.cpp
./main.out

Production:

f
f
static void N::C::f(int) [with T = char]
static void N::C::f(double) [with T = void]

Vous pouvez également être intéressé par les traces de pile avec des noms de fonction: imprimer la pile d'appels en C ou C ++

Testé dans 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 est entré en C ++ 20, nous avons donc encore une autre façon de le faire.

La documentation dit:

constexpr const char * nom_fonction () const noexcept;

6 Renvoie: si cet objet représente une position dans le corps d'une fonction, renvoie un NTBS défini par l'implémentation qui doit correspondre au nom de la fonction. Sinon, renvoie une chaîne vide.

où NTBS signifie "Chaîne d'octets terminée Null".

Je vais essayer quand le support arrivera à GCC, GCC 9.1.0 g++-9 -std=c++2ane le supporte toujours pas.

https://en.cppreference.com/w/cpp/utility/source_location les réclamations seront comme:

#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!");
}

Sortie possible:

info:main.cpp:16:main Hello world!

notez donc comment cela renvoie les informations sur l'appelant et est donc parfait pour une utilisation dans la journalisation, voir aussi: Existe - t-il un moyen d'obtenir le nom de la fonction dans une fonction C ++?

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

__func__est documenté dans la norme C ++ 0x à la section 8.4.1. Dans ce cas, il s'agit d'une variable locale de fonction prédéfinie de la forme:

static const char __func__[] = "function-name ";

où "nom de fonction" est spécifique à l'implémentation. Cela signifie que chaque fois que vous déclarez une fonction, le compilateur ajoute implicitement cette variable à votre fonction. Il en va de même pour __FUNCTION__et __PRETTY_FUNCTION__. Malgré leur majuscule, ce ne sont pas des macros. Bien que __func__soit un ajout à C ++ 0x

g++ -std=c++98 ....

compilera toujours le code en utilisant __func__.

__PRETTY_FUNCTION__et __FUNCTION__sont documentés ici http://gcc.gnu.org/onlinedocs/gcc-4.5.1/gcc/Function-Names.html#Function-Names . __FUNCTION__est juste un autre nom pour __func__. __PRETTY_FUNCTION__est le même qu'en __func__C mais en C ++ il contient également la signature de type.

sashang
la source
__func__ne fait pas partie de C ++ 03. Il a été ajouté en C ++ 0x, mais C ++ 0x n'est pas encore "la norme C ++", il est toujours sous forme de brouillon.
James McNellis
2
@JamesMcNellis Il est maintenant, alors effacez les commentaires, de supprimer le bruit
daramarak
7

Pour ceux qui se demandent comment ça se passe en VS.

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>();
}

production:

de main ():
principale
principale
int __cdecl main (vide)

de A :: f ():
A <int, float> :: f
F
void __cdecl A <int, float> :: f <bool> (void)

Utilisation de __PRETTY_FUNCTION__déclencheurs d'erreur d'identification non déclarée, comme prévu.

finnan
la source