web-dev-qa-db-fra.com

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

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

197
Matt Joiner

__func__ est un identificateur déclaré implicitement qui se transforme en une variable de tableau de caractères contenant le nom de la fonction lorsqu'elle est utilisée à l'intérieur d'une fonction. Il a été ajouté à C dans C99. De C99 §6.4.2.2/1:

L'identifiant __func__ est déclaré implicitement 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 englobant lexicalement. Ce nom est le nom sans fioritures de la fonction.

Notez que ce n’est pas une macro et qu’il n’a aucune signification particulière lors du prétraitement.

__func__ a été ajouté à C++ dans C++ 11, où il est spécifié qu'il contient "une chaîne définie par l'implémentation" (C++ 11, §8.4.1 [dcl.fct.def.general]/8), ce qui n’est pas aussi utile que la spécification en C. (La proposition originale d’ajouter __func__ à C++ était N1642 ).

__FUNCTION__ est une extension pré-standard prise en charge par certains compilateurs C (notamment gcc et Visual C++); en général, vous devez utiliser __func__ où il est pris en charge et n'utilisez que __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 le fait pas encore). supporte tout C++ 0x, ne fournit pas __func__).

__PRETTY_FUNCTION__ est une extension gcc qui est généralement identique à __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 souhaiterez 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 gcc sont décrites dans la page de la documentation gcc "Noms de fonction en tant que chaînes."

240
James McNellis

Bien que nous n’ayons pas répondu complètement à la question initiale, c’est probablement ce que la plupart des gens qui recherchaient sur Google voulaient voir.

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**)
88
Petr

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

#include <iostream>

namespace N {
    class C {
        public:
            template <class T>
            static void f(int i) {
                std::cout << __func__ << std::endl
                          << __FUNCTION__ << std::endl
                          << __PRETTY_FUNCTION__ << std::endl;
            }
            template <class T>
            static void f(double f) {
                std::cout << __PRETTY_FUNCTION__ << std::endl;
            }
    };
}

int main() {
    N::C::f<char>(1);
    N::C::f<void>(1.0);
}

Sortie GCC 7.2 g++ -std=gnu++98:

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 les noms de fonction: pile d’appel d’appel en C ou C++

C++ 20 source_location::function_name

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1208r5.pdf est passé en C++ 20, nous avons donc un autre moyen de le faire il.

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, retourne un NTBS défini par l'implémentation qui devrait correspondre au nom de la fonction. Sinon, renvoie une chaîne vide.

où NTBS signifie "chaîne d'octets nuls terminés".

Je vais essayer quand le support arrive à GCC, GCC 9.1.0 avec g++-9 -std=c++2a ne le supporte toujours pas.

__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 l'implémentation spécfic. Cela signifie que chaque fois que vous déclarez une fonction, le compilateur ajoutera implicitement cette variable à votre fonction. Il en va de même pour __FUNCTION__ et __PRETTY_FUNCTION__. Malgré leur majuscule, ils 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 identique à __func__ en C mais en C++, il contient également la signature de type.

12
sashang

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

MSVC 2015 Update 1, version de 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>();
}

sortie:

 from main (): 
 main 
 maine 
 int __cdecl maine (vide) 
 
 de A :: f () : 
 A <int, float> :: f 
 F 
 Void __cdecl A <int, float> :: f & ltbool> (void) 

L'utilisation de __PRETTY_FUNCTION__ déclenche une erreur d'identificateur non déclarée, comme prévu.

5
finnan