Das Makro __FILE__ zeigt den vollständigen Pfad an

Lesezeit: 3 Minuten

Benutzeravatar von mahmood
Mahmud

Das standardmäßige vordefinierte Makro __FILE__ verfügbar in C zeigt den vollständigen Pfad zur Datei. Gibt es eine Möglichkeit den Weg abzukürzen? Ich meine statt

/full/path/to/file.c

Aha

to/file.c

oder

file.c

  • Es wäre wirklich toll, eine reine Präprozessorlösung zu finden. Ich befürchte, dass die auf String-Operationen basierenden Vorschläge zur Laufzeit ausgeführt werden.

    – cdleonard

    13. Dezember 2011 um 11:26 Uhr

  • Da Sie gcc verwenden, können Sie meiner Meinung nach was ändern __FILE__ enthält, indem Sie den Dateinamen ändern, den Sie auf der Befehlszeile übergeben. Also statt gcc /full/path/to/file.cVersuchen cd /full/path/to; gcc file.c; cd -;. Natürlich gehört noch etwas mehr dazu, wenn Sie sich für den Include-Pfad oder den Speicherort der Ausgabedatei auf das aktuelle Verzeichnis von gcc verlassen. Bearbeiten: Die gcc-Dokumente deuten darauf hin, dass es sich um den vollständigen Pfad handelt. nicht das Argument für den Eingabedateinamen, aber das sehe ich nicht für gcc 4.5.3 auf Cygwin. Sie können es also auch unter Linux ausprobieren und sehen.

    – Steve Jessop

    13. Dezember 2011 um 11:44 Uhr


  • GCC 4.5.1 (speziell für arm-none-eabi gebaut) verwendet den genauen Text des Dateinamens in seiner Befehlszeile. In meinem Fall war es die Schuld der IDE, GCC mit allen vollständig qualifizierten Dateinamen aufzurufen, anstatt das aktuelle Verzeichnis irgendwo sinnvoll (Speicherort der Projektdatei, vielleicht?) oder konfigurierbar abzulegen und von dort aus relative Pfade zu verwenden. Ich vermute, dass viele IDEs dies tun (insbesondere unter Windows), weil es ihnen unangenehm ist, zu erklären, wo sich das “aktuelle” Verzeichnis für eine GUI-App wirklich befindet.

    – RBerteig

    13. September 2012 um 21:03 Uhr

  • @SteveJessop – hoffe du liest diesen Kommentar. Ich habe eine Situation, in der ich sehe __FILE__ gedruckt als ../../../../../../../../rtems/c/src/lib/libbsp/sparc/leon2/../../shared/bootcard.c und ich möchte wissen, wo gcc die Datei so kompiliert hat, dass diese Datei relativ so angeordnet ist, wie sie gezeigt wird.

    – Chan-Kim

    14. September 2014 um 4:32 Uhr


  • Diese Frage ist kein Dupe der verlinkten. Zum einen geht es im verlinkten um C++, und die Antworten vertiefen sich folglich in die C++-Makro-Esoterik. Zweitens enthält die Frage von OP nichts, was eine Makrolösung vorschreibt. Es weist nur feierlich auf ein Problem hin und stellt eine offene Frage.

    – Prof. Falken

    8. Juni 2015 um 17:53 Uhr

Hier ist ein Tipp, wenn Sie cmake verwenden. Aus:
http://public.kitware.com/pipermail/cmake/2013-January/053117.html

Ich kopiere den Tipp, damit alles auf dieser Seite steht:

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D__FILENAME__='\"$(subst
  ${CMAKE_SOURCE_DIR}/,,$(abspath $<))\"'")

Wenn Sie GNU make verwenden, sehe ich keinen Grund, warum Sie dies nicht auf Ihre eigenen Makefiles erweitern könnten. Sie könnten zum Beispiel eine Zeile wie diese haben:

CXX_FLAGS+=-D__FILENAME__='\"$(subst $(SOURCE_PREFIX)/,,$(abspath $<))\"'"

wo $(SOURCE_PREFIX) ist das Präfix, das Sie entfernen möchten.

Dann benutze __FILENAME__ anstelle von __FILE__.

  • Ich fürchte, dann funktioniert das nicht für die DATEI in Header-Datei referenziert.

    – Baiyan Huang

    12. September 2013 um 1:55 Uhr

  • Stimme @BaiyanHuang zu, bin mir aber nicht sicher, ob der Kommentar klar ist. __FILE__ ist kein einfaches Präprozessorsymbol, es wechselt zur aktuellen Datei und wird oft verwendet, um den Namen der aktuellen Datei (Header oder Quellmodul) auszugeben. Dies __FILENAME__ hätte nur die äußerste Quelle

    – nö

    1. Mai 2014 um 19:59 Uhr


  • Die Lösung dieser Antwort ist nicht portabel, da sie Bourne-Shell-Escapes verwendet. Verwenden Sie besser CMake, um es sauber und portabel zu implementieren. Sehen Sie sich hier die Antwort auf das Makro define_file_basename_for_sources an.

    – Colin D. Bennett

    16. Januar 2015 um 18:29 Uhr

  • Die GNU Make-Variante davon ist CFLAGS += -D__FILENAME__=\”$(notdir $<)\"

    – ctuffli

    7. Juli 2017 um 20:56 Uhr


  • @firegurafiku Auf eingebetteten Plattformen ist die Codegröße oft eher eine Einschränkung als die Geschwindigkeit. Wenn Sie Debug-Anweisungen in jeder Datei haben, kann das schnell die Dateigröße mit vollständigen Pfadzeichenfolgen erhöhen. Ich beschäftige mich gerade mit einer solchen Plattform und referenziere __FILE__ Überall sprengt der Code-Raum.

    – mrtumnus

    2. Februar 2018 um 14:45 Uhr


  • Das habe ich zunächst nicht verstanden. Ich habe Beispiele codiert und sie gegen gcc und clang laufen lassen und sie funktionieren. Ich experimentiere auch damit, einfach verschiedene wörtliche numerische Werte anzuhängen, und das verhält sich wie erwartet. Dann dämmerte es mir endlich. __FILE__ ist ein Zeiger auf ein Array von Bytes. Das Hinzufügen eines numerischen Literals ist also nur eine Zeigeraddition. Sehr schlau @RenatoUtsch

    – Daniel

    2. Juli 2018 um 15:30 Uhr


  • Es funktioniert nur, wenn sich eine Quelldatei im Verzeichnis cmake list befindet. Wenn sich eine Quelldatei außerhalb befindet, wird sie beschädigt, möglicherweise bei Zugriff außerhalb einer Literalzeichenfolge. Seien Sie also vorsichtig damit.

    – Andry

    23. Januar 2019 um 17:17 Uhr


  • Es reduziert tatsächlich nicht die Codegröße. Ich denke, der gesamte Pfad ist immer noch in die Binärdatei kompiliert, nur der Zeiger wird geändert.

    – Tarion

    20. Februar 2019 um 10:29 Uhr

  • Beide __FILE__ -Makro und die SOURCE_PATH_SIZE-Makros sind Konstanten, die zur Kompilierzeit bekannt sind. Ich würde erwarten, dass moderne Optimierungscompiler erkennen können, dass ein Teil der Zeichenfolge nicht verwendet wird, und ihn einfach aus der Binärdatei entfernen. Wie auch immer, ich glaube nicht, dass diese wenigen Bytes einen signifikanten Unterschied in der Binärgröße machen würden, also würde ich mich nicht wirklich darum kümmern.

    – Renato Utsch

    20. Februar 2019 um 17:38 Uhr


  • @RenatoUtsch Das Projekt, an dem ich arbeite, hat eine Änderung, die nur den Dateinamen angibt, aber den Nachteil hat, dass der Header auch den C-Dateinamen erhält. Die Änderung wurde vorgenommen, um reproduzierbare Builds zu erhalten. Würde also mit gcc mit -O2 der String tatsächlich optimiert und der Build reproduzierbar gemacht?

    – Paul Stelian

    4. Dezember 2019 um 15:34 Uhr

Benutzeravatar von simon.watts
simon.watts

GCC 8 hat jetzt die -fmacro-prefix-map und -ffile-prefix-map Optionen:

-fmacro-prefix-map=alt=Neu

Bei der Vorverarbeitung von Dateien, die sich im Verzeichnis befinden alterweitere das __FILE__ und __BASE_FILE__ Makros, als ob sich die Dateien im Verzeichnis befinden würden Neu stattdessen. Dies kann verwendet werden, um einen absoluten Pfad mit in einen relativen Pfad umzuwandeln . zum Neu was zu besser reproduzierbaren Builds führen kann, die ortsunabhängig sind. Diese Option wirkt sich auch aus __builtin_FILE() beim Kompilieren. Siehe auch -ffile-prefix-map.

-ffile-prefix-map=alt=Neu

Beim Kompilieren von Dateien, die sich im Verzeichnis befinden altzeichnen Sie alle Verweise auf sie im Ergebnis der Kompilierung auf, als ob sich die Dateien im Verzeichnis befinden würden Neu stattdessen. Die Angabe dieser Option entspricht der Angabe aller Personen -f*-prefix-map Optionen. Dies kann verwendet werden, um reproduzierbare Builds zu erstellen, die standortunabhängig sind. Siehe auch
-fmacro-prefix-map und -fdebug-prefix-map.

Festlegen eines ungültigen Pfads für -ffile-prefix-map (-fdebug-prefix-map) wird das Debuggen unterbrechen, es sei denn, Sie sagen Ihrem Debugger, wie er zurückzuordnen soll. (gdb: set substitue-pathvscode: "sourceFileMap").

Wenn Sie nur aufräumen wollen __FILE__ benutz einfach -fmacro-prefix-map.

Beispiel: Also für meine Jenkins Builds werde ich hinzufügen -ffile-prefix-map=${WORKSPACE}/=/und eine weitere, um das Installationspräfix des lokalen Entwicklungspakets zu entfernen.

HINWEIS Leider die -ffile-prefix-map und -fmacro-prefix-map Optionen sind erst ab GCC 8 verfügbar. Für, sagen wir, GCC 5 haben wir nur -fdebug-prefix-map was keinen Einfluss hat __FILE__.

  • Möglichkeit -ffile-prefix-map impliziert tatsächlich beides -fdebug-prefix-map und -fmacro-prefix-map Optionen. Siehe auch die Referenzen unter reproducible-builds.org/docs/build-path Der GCC-Bug, der aufspürt -fmacro-prefix-map und -ffile-prefix-map ist gcc.gnu.org/bugzilla/show_bug.cgi?id=70268

    – Lekenstein

    21. Januar 2019 um 10:26 Uhr


  • Wenn Ihr Compiler dies unterstützt, wie es jede einigermaßen aktuelle Version von GCC oder Clang tut, sollten Sie diese anstelle der anderen Lösungen verwenden. Es ist so viel eleganter und leichter.

    – Okrokette

    1. Juni um 16:48 Uhr

  • C++11
  • msvc2015u3,gcc5.4,clang3.8.0

    template <typename T, size_t S>
    inline constexpr size_t get_file_name_offset(const T (& str)[S], size_t i = S - 1)
    {
        return (str[i] == "https://stackoverflow.com/" || str[i] == '\\') ? i + 1 : (i > 0 ? get_file_name_offset(str, i - 1) : 0);
    }
    
    template <typename T>
    inline constexpr size_t get_file_name_offset(T (& str)[1])
    {
        return 0;
    }
    

    int main()
    {
         printf("%s\n", &__FILE__[get_file_name_offset(__FILE__)]);
    }
    

Code generiert einen Kompilierzeitversatz, wenn:

  • gcc: mindestens gcc6.1 + -O1
  • msvc: Ergebnis in constexpr-Variable einfügen:

      constexpr auto file = &__FILE__[get_file_name_offset(__FILE__)];
      printf("%s\n", file);
    
  • clang: bleibt bei Auswertung der Kompilierzeit bestehen

Es gibt einen Trick, um zu erzwingen, dass alle 3 Compiler auch in der Debug-Konfiguration mit deaktivierter Optimierung die Kompilierungszeit auswerten:

    namespace utility {

        template <typename T, T v>
        struct const_expr_value
        {
            static constexpr const T value = v;
        };

    }

    #define UTILITY_CONST_EXPR_VALUE(exp) ::utility::const_expr_value<decltype(exp), exp>::value

    int main()
    {
         printf("%s\n", &__FILE__[UTILITY_CONST_EXPR_VALUE(get_file_name_offset(__FILE__))]);
    }

https://godbolt.org/z/u6s8j3

  • Möglichkeit -ffile-prefix-map impliziert tatsächlich beides -fdebug-prefix-map und -fmacro-prefix-map Optionen. Siehe auch die Referenzen unter reproducible-builds.org/docs/build-path Der GCC-Bug, der aufspürt -fmacro-prefix-map und -ffile-prefix-map ist gcc.gnu.org/bugzilla/show_bug.cgi?id=70268

    – Lekenstein

    21. Januar 2019 um 10:26 Uhr


  • Wenn Ihr Compiler dies unterstützt, wie es jede einigermaßen aktuelle Version von GCC oder Clang tut, sollten Sie diese anstelle der anderen Lösungen verwenden. Es ist so viel eleganter und leichter.

    – Okrokette

    1. Juni um 16:48 Uhr

Zumindest für gcc ist der Wert von __FILE__ ist der Dateipfad wie in der Befehlszeile des Compilers angegeben. Wenn Sie kompilieren file.c so was:

gcc -c /full/path/to/file.c

das __FILE__ wird erweitern "/full/path/to/file.c". Wenn Sie stattdessen Folgendes tun:

cd /full/path/to
gcc -c file.c

dann __FILE__ wird auf nur erweitern "file.c".

Dies kann praktisch sein oder auch nicht.

Der C-Standard fordert dieses Verhalten nicht. Alles, was es darüber sagt __FILE__ ist, dass es erweitert wird zu “Der angenommene Name der aktuellen Quelldatei (ein Zeichenkettenliteral)”.

Eine Alternative ist die Verwendung von #line Richtlinie. Es überschreibt die aktuelle Zeilennummer und optional den Namen der Quelldatei. Wenn Sie den Dateinamen überschreiben, aber die Zeilennummer unverändert lassen möchten, verwenden Sie die __LINE__ Makro.

Sie können dies beispielsweise oben in hinzufügen file.c:

#line __LINE__ "file.c"

Das einzige Problem dabei ist, dass es der angegebenen Zeilennummer zuweist folgende Zeile und das erste Argument zu #line muss ein sein Ziffernfolge also kann man sowas nicht machen

#line (__LINE__-1) "file.c"  // This is invalid

Sicherstellen, dass der Dateiname in der #line Direktive mit dem tatsächlichen Namen der Datei übereinstimmt, bleibt als Übung übrig.

Zumindest für gcc wirkt sich dies auch auf den in Diagnosemeldungen gemeldeten Dateinamen aus.

  • Keith Thompson, es ist eine großartige Lösung, danke. Das einzige Problem ist, dass es scheint, dass dieses Makro schneidet __LINE__ Wert um eins. So __LINE__ Zeile geschrieben x gest ausgewertet werden x-1. Zumindest mit gcc 5.4.

    – elklepo

    6. November 2018 um 23:23 Uhr


  • @Klepak: Du hast Recht, und das ist Standardverhalten. Die Direktive “bewirkt, dass sich die Implementierung so verhält, als ob die folgende Sequenz von Quellzeilen mit einer Quellzeile beginnt, die eine Zeilennummer hat, die durch die Ziffernfolge angegeben ist”. Und es muss ein Ziffernfolgealso kannst du nicht verwenden #line __LINE__-1, "file.c". Ich werde meine Antwort aktualisieren.

    – Keith Thompson

    7. November 2018 um 2:11 Uhr

  • Wie wäre es für andere Compiler wie Clang, MSVC oder Intel C Compiler?

    – Franklin Yu

    30. Dezember 2019 um 9:38 Uhr

  • In Zeile 0 einer Datei mache ich einfach: #line 2 "name.cpp". Auch als Randnotiz ist es schön zu wissen, dass andere Dateien dadurch nicht kontaminiert werden #include es (zumindest auf MSVC)

    – Matt Eding

    14. April 2021 um 18:44 Uhr

1425740cookie-checkDas Makro __FILE__ zeigt den vollständigen Pfad an

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy