Quelle est la différence entre __PRETTY_FUNCTION__
, __FUNCTION__
, __func__
et où sont-ils documentés? Comment puis-je décider lequel utiliser?
__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éclarationstatic 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."
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**)
__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.
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.