Verwendung von __FILE__, __LINE__ und __FUNCTION__ in C ++

158

Vorausgesetzt , dass Ihre C ++ Compiler unterstützt sie, gibt es einen bestimmten Grund , nicht zu verwenden __FILE__, __LINE__und __FUNCTION__für die Protokollierung und Debugging - Zwecke?

Es geht mir in erster Linie darum, dem Benutzer irreführende Daten zu geben - beispielsweise die falsche Zeilennummer oder Funktion als Ergebnis der Optimierung zu melden - oder einen Leistungseinbruch zu erzielen.

Grundsätzlich kann ich vertrauen __FILE__, __LINE__und __FUNCTION__zu immer das Richtige zu tun?

Runcible
quelle
LINE sollte das Richtige tun. Ich habe es und seine Kohorten ausgiebig genutzt, einschließlich PRETTY_FUNCTION . ... Aber ... nun, ich schaue mir gerade den Code an, in dem LINE liegt. Wahrscheinlich, weil es sich in einem Catch-Block für die Behandlung von Try / Catch-Ausnahmen befindet.
Krazy Glew
4
relevant: gcc Referenz für vordefinierte Makros
Alexander Malakhov

Antworten:

191

__FUNCTION__ist nicht Standard, __func__existiert in C99 / C ++ 11. Die anderen ( __LINE__und __FILE__) sind in Ordnung.

Es wird immer die richtige Datei und Zeile gemeldet (und die Funktion, wenn Sie __FUNCTION__/ verwenden möchten __func__). Die Optimierung spielt keine Rolle, da es sich um eine Makroerweiterung zur Kompilierungszeit handelt. Es wird niemals die Leistung in irgendeiner Weise beeinträchtigen.

Evan Teran
quelle
3
__func__ist eine Art Problem in C ++. C99 sagt kein Wort über Standardargumente usw. Fälle, in denen es nicht so offensichtlich ist, wie __func__sich C ++ verhalten soll.
Wilhelmtell
4
@thr: während du einen guten Punkt machst. Mir war ziemlich klar, dass __func__es in c99 existiert, nicht in c ++. Unabhängig davon denke ich, dass eine vernünftige Implementierung von __func__in c ++ nur zu dem verstümmelten Namen führen würde. Da ich kein Compiler-Autor bin, ist es nicht wirklich mein Aufruf.
Evan Teran
Welche Compiler unterstützen das __FUNCTION__überhaupt nicht? Welche Compiler außer gcc behandeln dies als Variable und nicht als Makro?
Becken
36
__func__ist jetzt in C ++ 11 Standard.
VX
38

In seltenen Fällen kann es nützlich sein, die von __LINE__etwas gegebene Zeile zu ändern . Ich habe gesehen, dass GNU configure dies für einige Tests tut, um entsprechende Zeilennummern zu melden, nachdem zwischen Zeilen, die nicht in Originalquelldateien enthalten sind, Voodoo eingefügt wurde. Beispielsweise:

#line 100

Die folgenden Zeilen beginnen mit __LINE__100. Sie können optional einen neuen Dateinamen hinzufügen

#line 100 "file.c"

Es ist nur selten nützlich. Aber wenn es gebraucht wird, gibt es keine Alternativen, die ich kenne. Anstelle der Zeile kann auch ein Makro verwendet werden, das zu einer der beiden oben genannten Formen führen muss. Mit der Boost-Präprozessor-Bibliothek können Sie die aktuelle Zeile um 50 erhöhen:

#line BOOST_PP_ADD(__LINE__, 50)

Ich fand es nützlich, es zu erwähnen, da Sie nach der Verwendung von __LINE__und gefragt haben __FILE__. Man bekommt nie genug Überraschungen aus C ++ :)

Edit: @Jonathan Leffler bietet einige weitere gute Anwendungsfälle in den Kommentaren:

Das Spielen mit #line ist sehr nützlich für Vorprozessoren, die Fehler im C-Code des Benutzers in Übereinstimmung mit der Quelldatei des Benutzers halten möchten. Yacc, Lex und (für mich eher zu Hause) ESQL / C-Präprozessoren tun dies.

Johannes Schaub - litb
quelle
29

Zu Ihrer Information: g ++ bietet das nicht standardmäßige Makro __PRETTY_FUNCTION__ an. Bis jetzt wusste ich nichts über C99 __func__ (danke Evan!). Ich glaube, ich bevorzuge immer noch __PRETTY_FUNCTION__, wenn es für das zusätzliche Klassen-Scoping verfügbar ist.

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. */
}
Mr.Ree
quelle
2
Gut zu wissen über die __PRETTY_FUNCTION__. Sehr hilfreich!
Zheng Qu
8

Persönlich zögere ich, diese für etwas anderes als das Debuggen von Nachrichten zu verwenden. Ich habe es getan, aber ich versuche, Kunden oder Endbenutzern diese Art von Informationen nicht zu zeigen. Meine Kunden sind keine Ingenieure und manchmal nicht mit Computern vertraut. Ich könnte diese Informationen in der Konsole protokollieren, aber wie gesagt nur ungern, außer bei Debug-Builds oder internen Tools. Ich nehme an, es hängt jedoch von Ihrem Kundenstamm ab.

Craig S.
quelle
29
"Ich könnte diese Informationen in der Konsole protokollieren" - oder noch besser: Protokollieren Sie sie in einer Datei, damit Sie den Kunden bitten können, sie an Sie zu senden, wenn etwas schief geht ...
Christoph
7

C ++ 20 std::source_location

C ++ hat endlich eine Nicht-Makro-Option hinzugefügt, die wahrscheinlich irgendwann in der Zukunft dominieren wird, wenn C ++ 20 weit verbreitet wird:

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!

__PRETTY_FUNCTION__vs __FUNCTION__vs __func__vsstd::source_location::function_name

Beantwortet bei: Was ist der Unterschied zwischen __PRETTY_FUNCTION__, __FUNCTION__, __func__?

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
quelle
1
Es gibt <experimental/source_location>im aktuellen gcc-9.
陈浩南
5

Ich benutze sie die ganze Zeit. Das einzige, worüber ich mir Sorgen mache, ist, IP in Protokolldateien preiszugeben. Wenn Ihre Funktionsnamen wirklich gut sind, können Sie möglicherweise ein Geschäftsgeheimnis leichter aufdecken. Es ist wie beim Versand mit Debug-Symbolen, nur schwieriger zu finden. In 99,999% der Fälle wird nichts Schlimmes daraus.

JeffCharter
quelle
1
Guter Punkt, um zu erwähnen. Es ist trivial, diese Informationen mit dem stringsDienstprogramm zu extrahieren, um alle stringähnlichen Daten aus der ausführbaren Datei zu extrahieren. Sogar komprimierte ausführbare Dateien können extrahiert werden. Achten Sie sehr darauf, was Sie an einen Kunden senden. Oft können Konkurrenten Ihre ausführbaren Dateien in die Hände bekommen, obwohl sie dies nicht tun sollen.
Marty