181 votes

Utilisation de __FILE__, __LINE__ et __FUNCTION__ en C++.

En supposant que votre compilateur C++ les supporte, y a-t-il une raison particulière pas à utiliser __FILE__ , __LINE__ y __FUNCTION__ à des fins de journalisation et de débogage ?

Je suis surtout préoccupé par le fait de donner à l'utilisateur des données trompeuses - par exemple, signaler le mauvais numéro de ligne ou la mauvaise fonction à la suite de l'optimisation - ou de subir une baisse de performance en conséquence.

En gros, est-ce que je peux faire confiance __FILE__ , __LINE__ y __FUNCTION__ a toujours faire ce qu'il faut ?

0 votes

LIGNE devrait faire ce qu'il faut. Je l'ai largement utilisé, ainsi que ses cohortes, notamment pour JOLIE_FONCTION . ... Mais ... eh bien, je suis juste en train de regarder un code où LIGNE mensonges. Probablement parce qu'il se trouve dans un bloc catch pour la gestion des exceptions try/catch.

4 votes

214voto

Evan Teran Points 42370

__FUNCTION__ n'est pas standard, __func__ existe en C99 / C++11. Les autres ( __LINE__ y __FILE__ ) sont parfaits.

Il signalera toujours le bon fichier et la bonne ligne (et la bonne fonction si vous choisissez d'utiliser la fonction __FUNCTION__ / __func__ ). L'optimisation n'est pas un facteur, car il s'agit d'une expansion de macro au moment de la compilation. jamais affecter les performances de quelque manière que ce soit.

3 votes

__func__ est une sorte de problème en C++. Le C99 ne dit pas un mot sur les arguments par défaut et ainsi de suite, des cas où il n'est pas si évident de savoir comment utiliser les arguments par défaut. __func__ devrait se comporter en C++.

4 votes

@thr : bien que vous fassiez un bon point. J'ai été assez clair sur le fait que __func__ existe en c99, pas en c++. Quoi qu'il en soit, je pense qu'une implémentation raisonnable de __func__ en c++ donnerait juste un nom tronqué. Comme je ne suis pas un auteur de compilateur, ce n'est pas vraiment à moi de décider.

1 votes

Ce que les compilateurs ne supportent pas __FUNCTION__ du tout ? Quels compilateurs, à l'exception du récent gcc, traitent ceci comme une variable et non comme une macro ?

39voto

Dans de rares cas, il peut être utile de modifier la ligne qui est donnée par __LINE__ à quelque chose d'autre. J'ai vu GNU configure faire cela pour certains tests afin de rapporter les numéros de ligne appropriés après avoir inséré quelques voodoo entre des lignes qui n'apparaissent pas dans les fichiers sources originaux. Par exemple :

#line 100

Les lignes suivantes commenceront par __LINE__ 100. Vous pouvez éventuellement ajouter un nouveau nom de fichier

#line 100 "file.c"

Il n'est que rarement utile. Mais si c'est nécessaire, il n'y a pas d'alternative à ma connaissance. En fait, au lieu de la ligne, on peut aussi utiliser une macro qui doit aboutir à l'une des deux formes ci-dessus. En utilisant la bibliothèque du préprocesseur boost, vous pouvez incrémenter la ligne courante de 50 :

#line BOOST_PP_ADD(__LINE__, 50)

J'ai pensé qu'il était utile de le mentionner puisque vous avez demandé l'utilisation de __LINE__ y __FILE__ . On n'a jamais assez de surprises avec le C++ :)

Edit : @Jonathan Leffler fournit quelques autres bons cas d'utilisation dans les commentaires :

L'utilisation de #line est très utile pour les pré-processeurs qui veulent garder les erreurs signalées dans le code C de l'utilisateur en ligne avec le fichier source de l'utilisateur. C'est ce que font les préprocesseurs Yacc, Lex et (plus chez moi) ESQL/C.

32voto

Mr.Ree Points 5112

Pour info : g++ propose la macro non standard __PRETTY_FUNCTION__. Jusqu'à maintenant, je ne connaissais pas la __func__ de C99 (merci Evan !). Je pense que je préfère encore __PRETTY_FUNCTION__ lorsqu'elle est disponible pour le scoping de classe supplémentaire.

PS :

static string  getScopedClassMethod( string thePrettyFunction )
{
  size_t index = thePrettyFunction . find( "(" );
  if ( index == string::npos )
    return thePrettyFunction;  /* Degenerate case */

  thePrettyFunction . erase( index );

  index = thePrettyFunction . rfind( " " );
  if ( index == string::npos )
    return thePrettyFunction;  /* Degenerate case */

  thePrettyFunction . erase( 0, index + 1 );

  return thePrettyFunction;   /* The scoped class name. */
}

2 votes

C'est bon de connaître la __PRETTY_FUNCTION__. Très utile !

19voto

Ciro Santilli Points 3341

C++20 std::source_location

Le C++ a finalement ajouté une option non macro, et il est probable qu'elle dominera à un moment donné dans le futur lorsque le C++20 sera généralisé :

La documentation dit :

constexpr const char* function_name() const noexcept ;

6 Retour : Si cet objet représente une position dans le corps d'une fonction, renvoie 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 "Null Terminated Byte String".

La fonctionnalité est présente sur GCC 11.2 Ubuntu 21.10 avec -std=c++20 . Il ne l'était pas sur GCC 9.1.0 avec g++-9 -std=c++2a .

https://en.cppreference.com/w/cpp/utility/source_location montre que l'usage est :

main.cpp

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

Compilez et exécutez :

g++ -std=c++20 -Wall -Wextra -pedantic -o main.out main.cpp
./main.out

Sortie :

info:main.cpp:17:int main() Hello world!

__PRETTY_FUNCTION__ vs __FUNCTION__ vs __func__ vs std::source_location::function_name

Répondu à : Quelle est la différence entre __PRETTY_FUNCTION__, __FUNCTION__, __func__ ?

8voto

Craig S Points 962

Personnellement, je suis réticent à l'idée de les utiliser pour autre chose que des messages de débogage. Je l'ai fait, mais j'essaie de ne pas montrer ce genre d'informations aux clients ou aux utilisateurs finaux. Mes clients ne sont pas des ingénieurs et n'ont parfois pas de connaissances en informatique. Il m'arrive de consigner ces informations dans la console, mais, comme je l'ai dit, à contrecœur, sauf pour les constructions de débogage ou pour les outils internes. Je suppose que cela dépend de la clientèle que vous avez, cependant.

31 votes

"Je pourrais enregistrer cette information dans la console" - ou mieux encore : l'enregistrer dans un fichier de sorte que si quelque chose ne va pas, vous pouvez demander au client de vous l'envoyer...

0 votes

@Christoph ...et n'oubliez pas de réduire, supprimer ou écraser ce type de fichier périodiquement. Sinon, le client pourrait se demander pourquoi son disque est plein un jour... :-)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X