Das Makro __FILE__ zeigt den vollständigen Pfad an
164
Das __FILE__in C verfügbare vordefinierte Standardmakro zeigt den vollständigen Pfad zur Datei an. Gibt es eine Möglichkeit, den Weg zu verkürzen? Ich meine statt
Es wäre wirklich großartig, eine reine Präprozessorlösung zu finden. Ich befürchte, dass die auf Zeichenfolgenoperationen basierenden Vorschläge zur Laufzeit ausgeführt werden.
cdleonard
9
Da Sie gcc verwenden, können Sie den Inhalt ändern, __FILE__indem Sie den Dateinamen ändern, den Sie in der Befehlszeile übergeben. Also statt gcc /full/path/to/file.cversuchen cd /full/path/to; gcc file.c; cd -;. Natürlich steckt noch ein bisschen mehr dahinter, wenn Sie sich für den Include-Pfad oder den Speicherort der Ausgabedatei auf das aktuelle Verzeichnis von gcc verlassen. Bearbeiten: Die gcc-Dokumente legen nahe, dass es sich um den vollständigen Pfad handelt, nicht um das Argument für den Namen der Eingabedatei, aber das ist nicht das, was ich für gcc 4.5.3 unter Cygwin sehe. Sie können es also auch unter Linux ausprobieren und sehen.
Steve Jessop
4
GCC 4.5.1 (speziell für arm-none-eabi entwickelt) verwendet den genauen Text des Dateinamens in der Befehlszeile. In meinem Fall war es die Schuld der IDE, GCC mit allen vollständig qualifizierten Dateinamen aufzurufen, anstatt das aktuelle Verzeichnis an einem sinnvollen (Speicherort der Projektdatei, vielleicht?) Oder konfigurierbar zu platzieren und relative Pfade von dort zu verwenden. Ich vermute, dass viele IDEs dies tun (insbesondere unter Windows), weil sie sich unwohl fühlen, wenn sie erklären, wo sich das "aktuelle" Verzeichnis wirklich für eine GUI-App befindet.
RBerteig
3
@SteveJessop - hoffe du hast diesen Kommentar gelesen. Ich habe eine Situation, in der ich __FILE__gedruckt sehe ../../../../../../../../rtems/c/src/lib/libbsp/sparc/leon2/../../shared/bootcard.cund ich möchte wissen, wo gcc die Datei so kompiliert hat, dass sich diese Datei relativ befindet, wie sie gezeigt wird.
Chan Kim
1
Diese Frage ist kein Betrug der verknüpften. Zum einen handelt es sich bei dem verknüpften um C ++, und die Antworten befassen sich folglich mit C ++ - Makro-Esoterik. Zweitens gibt es in der Frage von OP nichts, was eine Makrolösung vorschreibt. Es weist nur feierlich auf ein Problem hin und stellt eine offene Frage.
/ist ein gültiges Pfadtrennzeichen in Dateinamen, die an CreateFile () usw. übergeben werden. Dies bedeutet jedoch nicht immer, dass Sie /nur irgendwo in Windows verwenden können, da es eine Tradition (von CPM geerbt) gibt, die /als Argument an der Eingabeaufforderung verwendet wird. Ein Qualitätswerkzeug würde jedoch darauf achten, Dateinamen sowohl in Schrägstriche als auch in Schrägstriche zu unterteilen, um Probleme für Benutzer zu vermeiden, die diese verwenden können /.
RBerteig
5
@AmigableClarkKant, nein, Sie können beide Trennzeichen im selben Dateinamen mischen.
RBerteig
2
Wenn Ihre Plattform dies unterstützt, ist es char* fileName = basename(__FILE__); definitiv unter Linux und OS X vorhanden. Sie wissen jedoch nichts über Windows.
JeremyP
14
Dies könnte auf verkürzt werden strrchr("/" __FILE__, '/') + 1. Durch das Voranstellen von "/" __FILE__wird sichergestellt, dass strrchr etwas findet, und somit wird die Bedingung ?: Nicht mehr benötigt.
Wenn Sie GNU make verwenden, sehe ich keinen Grund, warum Sie dies nicht auf Ihre eigenen Makefiles ausweiten können. Zum Beispiel könnten Sie eine Zeile wie diese haben:
Ich fürchte, dann funktioniert dies nicht für die DATEI, auf die in der Header-Datei verwiesen wird.
Baiyan Huang
2
Stimmen Sie @BaiyanHuang zu, aber nicht sicher, ob der Kommentar klar ist. __FILE__ist kein einfaches Präprozessorsymbol, es ändert sich in die aktuelle Datei und wird häufig zum Ausgeben des Namens der aktuellen Datei (Header oder Quellmodul) verwendet. Dies __FILENAME__würde nur die äußerste Quelle haben
nhed
3
Die Lösung dieser Antwort ist nicht portierbar, da sie Bourne-Shell-Escapezeichen verwendet. Verwenden Sie CMake besser, um es sauber und tragbar zu implementieren. Siehe die Makroantwort define_file_basename_for_sources hier.
Colin D Bennett
3
Die GNU Make-Variante davon ist CFLAGS + = -D__FILENAME __ = "$ (notdir $ <)"
ctuffli
4
@firegurafiku Auf eingebetteten Plattformen ist die Codegröße häufig eher eine Einschränkung als die Geschwindigkeit. Wenn Sie Debug-Anweisungen in jeder Datei haben, kann dies die Dateigröße mit Zeichenfolgen mit vollem Pfad schnell erhöhen. Ich habe es im Moment mit einer solchen Plattform zu tun, und __FILE__überall zu referenzieren , sprengt den Code-Raum.
Mrtumnus
26
Ich habe gerade an eine großartige Lösung gedacht, die sowohl mit Quell- als auch mit Header-Dateien funktioniert, sehr effizient ist und die Kompilierungszeit auf allen Plattformen ohne compilerspezifische Erweiterungen unterstützt. Diese Lösung behält auch die relative Verzeichnisstruktur Ihres Projekts bei, sodass Sie wissen, in welchem Ordner sich die Datei befindet und nur relativ zum Stammverzeichnis Ihres Projekts.
Die Idee ist, die Größe des Quellverzeichnisses mit Ihrem Build-Tool zu ermitteln und es einfach dem __FILE__Makro hinzuzufügen , das Verzeichnis vollständig zu entfernen und nur den Dateinamen anzuzeigen, der in Ihrem Quellverzeichnis beginnt.
Das folgende Beispiel wird mit CMake implementiert, aber es gibt keinen Grund, warum es mit anderen Build-Tools nicht funktionieren würde, da der Trick sehr einfach ist.
Definieren Sie in der Datei CMakeLists.txt ein Makro mit der Länge des Pfads zu Ihrem Projekt in CMake:
# The additional / is important to remove the last character from the path.# Note that it does not matter if the OS uses / or \, because we are only# saving the path size.
string(LENGTH "${CMAKE_SOURCE_DIR}/" SOURCE_PATH_SIZE)
add_definitions("-DSOURCE_PATH_SIZE=${SOURCE_PATH_SIZE}")
Definieren Sie in Ihrem Quellcode ein __FILENAME__Makro, das dem Makro nur die Quellpfadgröße hinzufügt __FILE__:
Verwenden Sie dann einfach dieses neue Makro anstelle des __FILE__Makros. Dies funktioniert, da der __FILE__Pfad immer mit dem Pfad zu Ihrem CMake-Quellverzeichnis beginnt. Durch Entfernen aus der __FILE__Zeichenfolge übernimmt der Präprozessor die Angabe des richtigen Dateinamens und alles relativ zum Stammverzeichnis Ihres CMake-Projekts.
Wenn Sie sich für die Leistung interessieren, ist dies genauso effizient wie die Verwendung __FILE__, da beide __FILE__und SOURCE_PATH_SIZEbekannte Kompilierungszeitkonstanten bekannt sind, sodass sie vom Compiler optimiert werden können.
Der einzige Ort, an dem dies fehlschlagen würde, ist, wenn Sie dies für generierte Dateien verwenden und diese sich in einem Off-Source-Build-Ordner befinden. Dann müssen Sie wahrscheinlich ein anderes Makro mit der CMAKE_BUILD_DIRVariablen anstelle von erstellen CMAKE_SOURCE_DIR.
Ich habe das zuerst nicht verstanden. Ich habe Beispiele codiert und sie gegen gcc und clang ausgeführt, und sie funktionieren. Ich experimentiere auch damit, nur verschiedene numerische Literalwerte 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 das Hinzufügen von Zeigern. Sehr klug @RenatoUtsch
Daniel
Dies funktioniert nur, wenn sich eine Quelldatei im Verzeichnis cmake list befindet. Wenn sich eine Quelldatei außerhalb befindet, wird sie beschädigt, möglicherweise mit Zugriff außerhalb einer Literalzeichenfolge. Also sei vorsichtig damit.
Andry
Die Codegröße wird dadurch nicht reduziert. Ich denke, der gesamte Pfad ist immer noch in die Binärdatei kompiliert, nur der Zeiger wird geändert.
Tarion
Sowohl das __FILE__Makro als auch das Makro SOURCE_PATH_SIZE sind Konstanten, die zur Kompilierungszeit bekannt sind. Ich würde erwarten, dass moderne Optimierungs-Compiler 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 bewirken würden, also würde mich das nicht wirklich interessieren.
RenatoUtsch
@RenatoUtsch Das Projekt, an dem ich arbeite, hat eine Änderung, die nur den Dateinamen angibt, aber den Nachteil hat, dass der C-Dateiname auch dem Header zugewiesen wird. 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
18
Zeitlösung hier rein kompilieren. Es basiert auf der Tatsache, dass sizeof()ein String-Literal seine Länge + 1 zurückgibt.
Sie können die bedingte Operatorkaskade auch auf den maximal sinnvollen Dateinamen im Projekt erweitern. Die Pfadlänge spielt keine Rolle, solange Sie weit genug vom Ende der Zeichenfolge entfernt prüfen.
Ich werde sehen, ob ich ein ähnliches Makro ohne fest codierte Länge mit Makrorekursion erhalten kann ...
Coole Antwort. Sie müssen mindestens -O1verwenden, um die Kompilierungszeit zu nutzen.
Digitales Trauma
1
Ist das nicht rückwärts? Sie möchten das letzte Vorkommen von '/' finden, was bedeutet, dass Sie zuerst mit der sizeof(s) > 2Prüfung beginnen sollten . Außerdem funktionierte dies zur Kompilierungszeit für mich bei -Os nicht. Die vollständigen Pfadzeichenfolgen waren in der Ausgabebinärdatei vorhanden.
Mrtumnus
15
Zumindest für gcc ist der Wert von __FILE__der Dateipfad, wie in der Befehlszeile des Compilers angegeben . Wenn Sie so kompilieren file.c:
gcc -c /full/path/to/file.c
das __FILE__wird sich erweitern auf "/full/path/to/file.c". Wenn Sie stattdessen Folgendes tun:
cd /full/path/to
gcc -c file.c
dann __FILE__wird auf nur erweitert "file.c".
Dies kann praktisch sein oder auch nicht.
Der C-Standard erfordert dieses Verhalten nicht. Alles, worüber es sagt, __FILE__ist, dass es auf "Der vermutete Name der aktuellen Quelldatei (ein Zeichenfolgenliteral)" erweitert wird.
Eine Alternative ist die Verwendung der #lineRichtlinie. Es überschreibt die aktuelle Zeilennummer und optional den Namen der Quelldatei. Wenn Sie den Dateinamen überschreiben möchten, aber die Zeilennummer in Ruhe lassen möchten, verwenden Sie das __LINE__Makro.
Zum Beispiel können Sie dies oben hinzufügen file.c:
#line __LINE__ "file.c"
Das einzige Problem dabei ist, dass die angegebene Zeilennummer der folgenden Zeile zugewiesen wird und das erste Argument #lineeine Ziffernfolge sein muss, damit Sie so etwas nicht tun können
#line(__LINE__-1)"file.c"// This is invalid
Es #linewird als Übung belassen, sicherzustellen, dass der Dateiname in der Direktive mit dem tatsächlichen Namen der Datei übereinstimmt.
Zumindest für gcc wirkt sich dies auch auf den in Diagnosemeldungen angegebenen Dateinamen aus.
Keith Thompson, es ist eine großartige Lösung, danke. Das einzige Problem ist, dass dieses Makro den __LINE__Wert anscheinend um eins senkt . So __LINE__geschrieben in Zeile xgest ausgewertet x-1. Zumindest mit gcc 5.4.
Elklepo
1
@Klepak: Du hast recht, und das ist Standardverhalten. Die Anweisung "bewirkt, dass sich die Implementierung so verhält, als ob die folgende Folge von Quellzeilen mit einer Quellzeile beginnt, deren Zeilennummer durch die Ziffernfolge angegeben ist". Und es muss eine Ziffernfolge sein , damit Sie sie nicht verwenden können #line __LINE__-1, "file.c". Ich werde meine Antwort aktualisieren.
Keith Thompson
1
Wie wäre es für andere Compiler wie Clang, MSVC oder Intel C Compiler?
Franklin Yu
7
Ein bisschen spät zur Party, aber für GCC schauen Sie sich die -ffile-prefix-map=old=newOption an:
Wenn Sie Dateien kompilieren, die sich im alten Verzeichnis befinden , notieren Sie im Ergebnis der Kompilierung alle Verweise darauf, als ob sich die Dateien stattdessen im neuen Verzeichnis befinden würden . Die Angabe dieser Option entspricht der Angabe aller einzelnen -f*-prefix-mapOptionen. Dies kann verwendet werden, um reproduzierbare Builds zu erstellen, die ortsunabhängig sind. Siehe auch
-fmacro-prefix-mapund -fdebug-prefix-map.
Also werde ich für meine Jenkins- Builds ein -ffile-prefix-map=${WORKSPACE}/=/weiteres hinzufügen , um das lokale Entwicklungspaket-Installationspräfix zu entfernen.
HINWEIS Leider ist die -ffile-prefix-mapOption nur ab GCC 8 verfügbar, ebenso wie -fmacro-prefix-mapdas, was meiner Meinung nach den __FILE__Teil ausmacht . Zum Beispiel für GCC 5 haben wir nur das, -fdebug-prefix-mapwas nicht (anscheinend) beeinflusst __FILE__.
template<typename T,size_t S>inlineconstexprsize_t get_file_name_offset(const T (& str)[S],size_t i = S -1){return(str[i]=='/'|| str[i]=='\\')? i +1:(i >0? get_file_name_offset(str, i -1):0);}template<typename T>inlineconstexprsize_t get_file_name_offset(T (& str)[1]){return0;}
'
int main(){
printf("%s\n",&__FILE__[get_file_name_offset(__FILE__)]);}
Code generiert einen Kompilierungszeitversatz, wenn:
clang: bleibt bei der Auswertung der Kompilierungszeit bestehen
Es gibt einen Trick, um zu erzwingen, dass alle 3 Compiler die Kompilierungszeitbewertung auch in der Debug-Konfiguration mit deaktivierter Optimierung durchführen:
namespace utility {template<typename T, T v>struct const_expr_value
{staticconstexprconst 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__))]);}
Es gibt keine Möglichkeit zur Kompilierung, um dies zu tun. Natürlich können Sie dies zur Laufzeit mit der C-Laufzeit tun, wie einige der anderen Antworten gezeigt haben, aber zur Kompilierungszeit, wenn der Präprozessor einschaltet, haben Sie kein Glück.
Die strrchrAntwort könnte plausibel zur Kompilierungszeit berechnet werden, obwohl dies natürlich immer noch nicht vom Präprozessor geschieht. Ich weiß nicht, ob gcc es tatsächlich tut, ich habe es nicht überprüft, aber ich bin mir ziemlich sicher, dass es strlenzur Kompilierungszeit aus String-Literalen berechnet .
Steve Jessop
@Steve - vielleicht, aber das ist eine große Abhängigkeit vom compilerspezifischen Verhalten.
Sean
Ich denke nicht, dass es eine große Abhängigkeit ist, da ich sehr bezweifle, dass dieser Code leistungskritisch ist. Und wenn ja, verschieben Sie es aus der Schleife. In Fällen, in denen dies eine große Sache ist, weil Sie unbedingt ein Zeichenfolgenliteral benötigen, das nur den Basisnamen enthält, können Sie möglicherweise die richtige Zeichenfolge zur Erstellungszeit berechnen , indem Sie ein Skript über die Quelle ausführen.
Steve Jessop
5
Es ist möglicherweise nicht leistungskritisch, kann jedoch leicht als datenschutzkritisch angesehen werden. Es gibt keinen wirklich guten Grund, meine organisatorischen Praktiken pro Kunde in Zeichenfolgen zu enthüllen, die in einer freigegebenen EXE-Datei eingefroren sind. Schlimmer noch, für Anwendungen, die im Auftrag eines Kunden erstellt wurden, können diese Zeichenfolgen Dinge enthüllen, die mein Kunde möglicherweise lieber nicht möchte, z. B. nicht der Autor seines eigenen Produkts zu sein. Da dies __FILE__implizit durch aufgerufen wird assert(), kann dieses Leck ohne jede andere offensichtliche Handlung auftreten.
RBerteig
@RBerteig Der Basisname __FILE__selbst kann auch Dinge enthüllen, die der Kunde möglicherweise lieber nicht möchte. Die Verwendung von __FILE__irgendwo überhaupt - unabhängig davon, ob er den vollständigen absoluten Pfadnamen oder nur den Basisnamen enthält - hat dieselben Probleme, auf die Sie hingewiesen haben. In dieser Situation muss die gesamte Ausgabe überprüft und eine spezielle API für die Ausgabe an Kunden eingeführt werden. Der Rest der Ausgabe sollte in / dev / NULL oder stdout ausgegeben und stderr sollte geschlossen werden. :-)
@ Mahmood : char file_copy[] = __FILE__; const char *filename = basename(__FILE__);. Der Grund für die Kopie ist, dass der Basisname die Eingabezeichenfolge ändern kann. Sie müssen auch darauf achten, dass der Ergebniszeiger nur gut ist, bis basenameer erneut aufgerufen wird. Dies bedeutet, dass es nicht threadsicher ist.
Steve Jessop
@SteveJessop, ah ich habe es vergessen. Wahr.
Prof. Falken
1
@Amigable: Um fair zu sein, ich vermute, basenamedass die daraus resultierende Eingabezeichenfolge tatsächlich nicht geändert wird __FILE__, da die Eingabezeichenfolge /am Ende keine hat und daher keine Änderungen erforderlich sind. Sie könnten also damit durchkommen, aber ich denke, wenn jemand das erste Mal sieht basename, sollte er es mit allen Einschränkungen sehen.
Steve Jessop
@SteveJessop In der BSd-Manpage für basename () wird erwähnt, dass die ältere Version von basename () ein const char * verwendet und die Zeichenfolge nicht ändert. Die Linux-Manpage erwähnt nichts über const, erwähnt aber, dass es einen Teil der Argumentzeichenfolge zurückgeben kann. Seien Sie also am besten konservativ im Umgang mit basename ().
Prof. Falken
@SteveJessop, hehe, ich habe nur jetzt nach sorgfältig auf Ihren Kommentar suchen, nach vier Jahren, realize , dass /ihr Argument am Ende des Strings Mittel Basisnamen kann einen guten Grund haben , zu ändern.
Prof. Falken
4
Wenn Sie CMAKEmit dem GNU-Compiler arbeiten global, funktioniert diese Definition einwandfrei:
-Wno-builtin-macro-redefinedum die Compiler-Warnungen für die Neudefinition des __FILE__Makros stummzuschalten.
Informationen zu Compilern, die dies nicht unterstützen, finden Sie im Abschnitt Robust .
Das Entfernen des Projektpfads vom Dateipfad ist Ihre eigentliche Anforderung. Sie möchten nicht die Zeit verschwenden, um herauszufinden, wo sich eine header.hDatei befindet, src/foo/header.hoder src/bar/header.h.
Wir sollten das __FILE__Makro in der cmakeKonfigurationsdatei entfernen.
Dieses Makro wird in den meisten vorhandenen Codes verwendet. Definieren Sie es einfach neu, um frei zu werden.
Compiler wie gccdefinieren dieses Makro anhand der Befehlszeilenargumente vor. Und der vollständige Pfad wird in makefiles geschrieben, das von generiert wird cmake.
Hardcode in CMAKE_*_FLAGSist erforderlich.
Es gibt einige Befehle zum Hinzufügen von Compileroptionen oder -definitionen in einer neueren Version, wie z . B. add_definitions()und add_compile_definitions(). Diese Befehle analysieren die make-Funktionen wie substzuvor für Quelldateien. Das wollen wir nicht.
Dies funktioniert nicht für Inhalte, die aus Include-Dateien stammen.
Chqrlie
Kannst du einen Code posten? Ein häufiger Fall besteht darin, Variablen im lokalen Bereich festzulegen und in einem anderen zu verwenden.
Levi.G
Wenn Sie beispielsweise __FILE__mit Ihrer Definition eine Diagnose in einer Inline-Funktion erstellen, die in einer Header-Datei definiert ist, meldet die Laufzeitdiagnose den Namen der an den Compiler übergebenen Datei anstelle des Namens der Include-Datei, während die Zeilennummer dies tun würde Siehe die Include-Datei.
Chqrlie
Ja, es wurde so konzipiert, dass es für die häufigste Verwendung ist #define LOG(fmt, args...) printf("%s " fmt, __FILE__, ##args). Wenn Sie das LOG()Makro verwenden, möchten Sie es nicht wirklich log.hin Nachrichten sehen. Schließlich wird das __FILE__Makro in jeder C / Cpp-Datei (Kompilierungseinheit) anstelle der enthaltenen Dateien erweitert.
Levi.G
3
Eine geringfügige Abweichung von dem, was @ red1ynx vorgeschlagen hat, wäre das Erstellen des folgenden Makros:
Ich habe ein Makro erstellt __FILENAME__, das es vermeidet, jedes Mal den vollen Pfad zu schneiden. Das Problem besteht darin, den resultierenden Dateinamen in einer cpp-lokalen Variablen zu speichern.
Dies kann einfach durch Definieren einer statischen globalen Variablen in der .h- Datei erfolgen. Diese Definition enthält separate und unabhängige Variablen in jeder CPP- Datei, die die .h- Datei enthält . Um ein Multithreading-Proof zu sein, lohnt es sich, die Variablen auch threadlokal (TLS) zu machen.
Eine Variable speichert den Dateinamen (verkleinert). Ein anderer enthält den nicht geschnittenen Wert, __FILE__der angegeben wurde. Die h-Datei:
Und die Funktion wird folgendermaßen implementiert:
constchar*GetSourceFileName(constchar* strFilePath,constchar*& rstrFilePathHolder,constchar*& rstrFileNameHolder){if(strFilePath != rstrFilePathHolder){// // This if works in 2 cases: // - when first time called in the cpp (ordinary case) or// - when the macro __FILENAME__ is used in both h and cpp files // and so the method is consequentially called // once with strFilePath == "UserPath/HeaderFileThatUsesMyMACRO.h" and // once with strFilePath == "UserPath/CPPFileThatUsesMyMACRO.cpp"//
rstrFileNameHolder = removePath(strFilePath);
rstrFilePathHolder = strFilePath;}return rstrFileNameHolder;}
Das removePath () kann auf verschiedene Arten implementiert werden, aber das schnelle und einfache scheint mit strrchr zu sein:
push_macround pop_macrosind nicht Standard. (gcc unterstützt sie aus Gründen der Kompatibilität mit Microsoft Windows-Compilern.) In jedem Fall macht es keinen Sinn, die Definition von zu verschieben und zu löschen __FILE__. Der wiederhergestellte Wert wird ohnehin nach dem Ende der Quelldatei nicht mehr verwendet. Eine sauberere Möglichkeit, den Wert von zu ändern, __FILE__ist#line __LINE__ "foobar.c"
Hier ist eine tragbare Funktion, die sowohl für Linux (Pfad '/') als auch für Windows (Mischung aus '\' und '/') funktioniert. Kompiliert mit gcc, clang und vs.
#include<string.h>#include<stdio.h>constchar*GetFileName(constchar*path){constchar*name = NULL,*tmp = NULL;if(path &&*path){
name = strrchr(path,'/');
tmp = strrchr(path,'\\');if(tmp){return name && name > tmp ? name +1: tmp +1;}}return name ? name +1: path;}int main(){constchar*name = NULL,*path = NULL;
path = __FILE__;
name =GetFileName(path);
printf("path: %s, filename: %s\n", path, name);
path ="/tmp/device.log";
name =GetFileName(path);
printf("path: %s, filename: %s\n", path, name);
path ="C:\\Downloads\\crisis.avi";
name =GetFileName(path);
printf("path: %s, filename: %s\n", path, name);
path ="C:\\Downloads/nda.pdf";
name =GetFileName(path);
printf("path: %s, filename: %s\n", path, name);
path ="C:/Downloads\\word.doc";
name =GetFileName(path);
printf("path: %s, filename: %s\n", path, name);
path = NULL;
name =GetFileName(NULL);
printf("path: %s, filename: %s\n", path, name);
path ="";
name =GetFileName("");
printf("path: %s, filename: %s\n", path, name);return0;}
Wenn Sie auf dieser Seite nach einer Möglichkeit gesucht haben, den absoluten Quellpfad, der auf einen hässlichen Build-Speicherort verweist, aus der von Ihnen gelieferten Binärdatei zu entfernen, entspricht dies möglicherweise Ihren Anforderungen.
Obwohl dies nicht genau die Antwort liefert, die der Autor gewünscht hat , da es die Verwendung von CMake voraussetzt , kommt es ziemlich nahe. Schade, dass dies zuvor von niemandem erwähnt wurde, da es mir viel Zeit gespart hätte.
OPTION(CMAKE_USE_RELATIVE_PATHS "If true, cmake will use relative paths" ON)
Wenn Sie die obige Variable auf setzen, ONwird ein Build-Befehl im folgenden Format generiert:
cd /ugly/absolute/path/to/project/build/src &&
gcc <.. other flags ..>-c ../../src/path/to/source.c
Infolgedessen wird das __FILE__Makro in aufgelöst../../src/path/to/source.c
In der Dokumentation zu CMake 3.4+ heißt es: "Diese Variable hat keine Auswirkung. Die teilweise implementierte Auswirkung, die sie in früheren Versionen hatte, wurde in CMake 3.4 entfernt." Wenn es mit 3.13 für Sie funktioniert hat, gibt es einen anderen Grund dafür.
__BASE_FILE__Dieses Makro wird auf den Namen der Haupteingabedatei in Form einer C-String-Konstante erweitert. Dies ist die Quelldatei, die in der Befehlszeile des Präprozessors oder C-Compilers angegeben wurde
und steuern Sie dann, wie Sie den Dateinamen anzeigen möchten, indem Sie die Darstellung der Quelldatei (vollständiger Pfad / relativer Pfad / Basisname) zur Kompilierungszeit ändern.
macht keinen Unterschied. Ich habe verwendet __FILE__und __BASE_FILE__jedoch zeigen beide den vollständigen Pfad zur Datei
Mahmood
Wie rufst du den Compiler auf?
ziu
2
Dann wette ich, dass SCONS so gcc anruft gcc /absolute/path/to/file.c. Wenn Sie einen Weg finden, dieses Verhalten zu ändern (eine weitere Frage zu SO, lol?), Müssen Sie die Zeichenfolge zur Laufzeit nicht ändern
ziu
17
Diese Antwort ist 100% falsch. __BASE_FILE__(wie in den Dokumenten angegeben, wenn auch unklar) erzeugt den Namen der in der Befehlszeile angegebenen Datei , z. B. test.coder /tmp/test.cabhängig davon, wie Sie den Compiler aufgerufen haben. Das ist genau das Gleiche wie __FILE__, außer wenn Sie sich in einer Header-Datei befinden. In diesem Fall __FILE__wird der Name der aktuellen Datei (z. B. foo.h) erzeugt, während __BASE_FILE__weiterhin produziert wird test.c.
Quuxplusone
0
Hier ist eine Lösung, die für Umgebungen funktioniert, in denen die Zeichenfolgenbibliothek nicht vorhanden ist (Linux-Kernel, eingebettete Systeme usw.):
Je nach Plattform möchten Sie möglicherweise sowohl '/' als auch '\' überprüfen.
Technophile
0
#include<algorithm>#include<string>usingnamespace std;
string f( __FILE__ );
f = string((find(f.rbegin(), f.rend(),'/')+1).base()+1, f.end());// searches for the '/' from the back, transfers the reverse iterator // into a forward iterator and constructs a new sting with both
__FILE__
indem Sie den Dateinamen ändern, den Sie in der Befehlszeile übergeben. Also stattgcc /full/path/to/file.c
versuchencd /full/path/to; gcc file.c; cd -;
. Natürlich steckt noch ein bisschen mehr dahinter, wenn Sie sich für den Include-Pfad oder den Speicherort der Ausgabedatei auf das aktuelle Verzeichnis von gcc verlassen. Bearbeiten: Die gcc-Dokumente legen nahe, dass es sich um den vollständigen Pfad handelt, nicht um das Argument für den Namen der Eingabedatei, aber das ist nicht das, was ich für gcc 4.5.3 unter Cygwin sehe. Sie können es also auch unter Linux ausprobieren und sehen.__FILE__
gedruckt sehe../../../../../../../../rtems/c/src/lib/libbsp/sparc/leon2/../../shared/bootcard.c
und ich möchte wissen, wo gcc die Datei so kompiliert hat, dass sich diese Datei relativ befindet, wie sie gezeigt wird.Antworten:
Versuchen
Verwenden Sie für Windows '\\' anstelle von '/'.
quelle
/
ist ein gültiges Pfadtrennzeichen in Windows./
ist ein gültiges Pfadtrennzeichen in Dateinamen, die an CreateFile () usw. übergeben werden. Dies bedeutet jedoch nicht immer, dass Sie/
nur irgendwo in Windows verwenden können, da es eine Tradition (von CPM geerbt) gibt, die/
als Argument an der Eingabeaufforderung verwendet wird. Ein Qualitätswerkzeug würde jedoch darauf achten, Dateinamen sowohl in Schrägstriche als auch in Schrägstriche zu unterteilen, um Probleme für Benutzer zu vermeiden, die diese verwenden können/
.char* fileName = basename(__FILE__);
definitiv unter Linux und OS X vorhanden. Sie wissen jedoch nichts über Windows.strrchr("/" __FILE__, '/') + 1
. Durch das Voranstellen von "/"__FILE__
wird sichergestellt, dass strrchr etwas findet, und somit wird die Bedingung ?: Nicht mehr benötigt.Hier ist ein Tipp, wenn Sie cmake verwenden. Von: http://public.kitware.com/pipermail/cmake/2013-January/053117.html
Ich kopiere den Tipp, damit alles auf dieser Seite steht:
Wenn Sie GNU make verwenden, sehe ich keinen Grund, warum Sie dies nicht auf Ihre eigenen Makefiles ausweiten können. Zum Beispiel könnten Sie eine Zeile wie diese haben:
Wo
$(SOURCE_PREFIX)
ist das Präfix, das Sie entfernen möchten?Dann
__FILENAME__
anstelle von verwenden__FILE__
.quelle
__FILE__
ist kein einfaches Präprozessorsymbol, es ändert sich in die aktuelle Datei und wird häufig zum Ausgeben des Namens der aktuellen Datei (Header oder Quellmodul) verwendet. Dies__FILENAME__
würde nur die äußerste Quelle haben__FILE__
überall zu referenzieren , sprengt den Code-Raum.Ich habe gerade an eine großartige Lösung gedacht, die sowohl mit Quell- als auch mit Header-Dateien funktioniert, sehr effizient ist und die Kompilierungszeit auf allen Plattformen ohne compilerspezifische Erweiterungen unterstützt. Diese Lösung behält auch die relative Verzeichnisstruktur Ihres Projekts bei, sodass Sie wissen, in welchem Ordner sich die Datei befindet und nur relativ zum Stammverzeichnis Ihres Projekts.
Die Idee ist, die Größe des Quellverzeichnisses mit Ihrem Build-Tool zu ermitteln und es einfach dem
__FILE__
Makro hinzuzufügen , das Verzeichnis vollständig zu entfernen und nur den Dateinamen anzuzeigen, der in Ihrem Quellverzeichnis beginnt.Das folgende Beispiel wird mit CMake implementiert, aber es gibt keinen Grund, warum es mit anderen Build-Tools nicht funktionieren würde, da der Trick sehr einfach ist.
Definieren Sie in der Datei CMakeLists.txt ein Makro mit der Länge des Pfads zu Ihrem Projekt in CMake:
Definieren Sie in Ihrem Quellcode ein
__FILENAME__
Makro, das dem Makro nur die Quellpfadgröße hinzufügt__FILE__
:Verwenden Sie dann einfach dieses neue Makro anstelle des
__FILE__
Makros. Dies funktioniert, da der__FILE__
Pfad immer mit dem Pfad zu Ihrem CMake-Quellverzeichnis beginnt. Durch Entfernen aus der__FILE__
Zeichenfolge übernimmt der Präprozessor die Angabe des richtigen Dateinamens und alles relativ zum Stammverzeichnis Ihres CMake-Projekts.Wenn Sie sich für die Leistung interessieren, ist dies genauso effizient wie die Verwendung
__FILE__
, da beide__FILE__
undSOURCE_PATH_SIZE
bekannte Kompilierungszeitkonstanten bekannt sind, sodass sie vom Compiler optimiert werden können.Der einzige Ort, an dem dies fehlschlagen würde, ist, wenn Sie dies für generierte Dateien verwenden und diese sich in einem Off-Source-Build-Ordner befinden. Dann müssen Sie wahrscheinlich ein anderes Makro mit der
CMAKE_BUILD_DIR
Variablen anstelle von erstellenCMAKE_SOURCE_DIR
.quelle
__FILE__
ist ein Zeiger auf ein Array von Bytes. Das Hinzufügen eines numerischen Literals ist also nur das Hinzufügen von Zeigern. Sehr klug @RenatoUtsch__FILE__
Makro als auch das Makro SOURCE_PATH_SIZE sind Konstanten, die zur Kompilierungszeit bekannt sind. Ich würde erwarten, dass moderne Optimierungs-Compiler 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 bewirken würden, also würde mich das nicht wirklich interessieren.Zeitlösung hier rein kompilieren. Es basiert auf der Tatsache, dass
sizeof()
ein String-Literal seine Länge + 1 zurückgibt.Sie können die bedingte Operatorkaskade auch auf den maximal sinnvollen Dateinamen im Projekt erweitern. Die Pfadlänge spielt keine Rolle, solange Sie weit genug vom Ende der Zeichenfolge entfernt prüfen.
Ich werde sehen, ob ich ein ähnliches Makro ohne fest codierte Länge mit Makrorekursion erhalten kann ...
quelle
-O1
verwenden, um die Kompilierungszeit zu nutzen.sizeof(s) > 2
Prüfung beginnen sollten . Außerdem funktionierte dies zur Kompilierungszeit für mich bei -Os nicht. Die vollständigen Pfadzeichenfolgen waren in der Ausgabebinärdatei vorhanden.Zumindest für gcc ist der Wert von
__FILE__
der Dateipfad, wie in der Befehlszeile des Compilers angegeben . Wenn Sie so kompilierenfile.c
:das
__FILE__
wird sich erweitern auf"/full/path/to/file.c"
. Wenn Sie stattdessen Folgendes tun:dann
__FILE__
wird auf nur erweitert"file.c"
.Dies kann praktisch sein oder auch nicht.
Der C-Standard erfordert dieses Verhalten nicht. Alles, worüber es sagt,
__FILE__
ist, dass es auf "Der vermutete Name der aktuellen Quelldatei (ein Zeichenfolgenliteral)" erweitert wird.Eine Alternative ist die Verwendung der
#line
Richtlinie. Es überschreibt die aktuelle Zeilennummer und optional den Namen der Quelldatei. Wenn Sie den Dateinamen überschreiben möchten, aber die Zeilennummer in Ruhe lassen möchten, verwenden Sie das__LINE__
Makro.Zum Beispiel können Sie dies oben hinzufügen
file.c
:Das einzige Problem dabei ist, dass die angegebene Zeilennummer der folgenden Zeile zugewiesen wird und das erste Argument
#line
eine Ziffernfolge sein muss, damit Sie so etwas nicht tun könnenEs
#line
wird als Übung belassen, sicherzustellen, dass der Dateiname in der Direktive mit dem tatsächlichen Namen der Datei übereinstimmt.Zumindest für gcc wirkt sich dies auch auf den in Diagnosemeldungen angegebenen Dateinamen aus.
quelle
__LINE__
Wert anscheinend um eins senkt . So__LINE__
geschrieben in Zeilex
gest ausgewertetx-1
. Zumindest mit gcc 5.4.#line __LINE__-1, "file.c"
. Ich werde meine Antwort aktualisieren.Ein bisschen spät zur Party, aber für GCC schauen Sie sich die
-ffile-prefix-map=old=new
Option an:Also werde ich für meine Jenkins- Builds ein
-ffile-prefix-map=${WORKSPACE}/=/
weiteres hinzufügen , um das lokale Entwicklungspaket-Installationspräfix zu entfernen.HINWEIS Leider ist die
-ffile-prefix-map
Option nur ab GCC 8 verfügbar, ebenso wie-fmacro-prefix-map
das, was meiner Meinung nach den__FILE__
Teil ausmacht . Zum Beispiel für GCC 5 haben wir nur das,-fdebug-prefix-map
was nicht (anscheinend) beeinflusst__FILE__
.quelle
-ffile-prefix-map
impliziert in der Tat beides-fdebug-prefix-map
und-fmacro-prefix-map
Optionen. Siehe auch die Verweise auf reproducible-builds.org/docs/build-path Die GCC Fehler , dass Titel-fmacro-prefix-map
und-ffile-prefix-map
ist gcc.gnu.org/bugzilla/show_bug.cgi?id=70268msvc2015u3, gcc5.4, clang3.8.0
'
Code generiert einen Kompilierungszeitversatz, wenn:
gcc
: mindestens gcc6.1 +-O1
msvc
: Ergebnis in constexpr Variable setzen:clang
: bleibt bei der Auswertung der Kompilierungszeit bestehenEs gibt einen Trick, um zu erzwingen, dass alle 3 Compiler die Kompilierungszeitbewertung auch in der Debug-Konfiguration mit deaktivierter Optimierung durchführen:
https://godbolt.org/z/u6s8j3
quelle
In VC, bei der Verwendung
/FC
,__FILE__
erweitert auf den vollständigen Pfad, ohne die/FC
Option__FILE__
Dateinamen erweitert. ref: hierquelle
Es gibt keine Möglichkeit zur Kompilierung, um dies zu tun. Natürlich können Sie dies zur Laufzeit mit der C-Laufzeit tun, wie einige der anderen Antworten gezeigt haben, aber zur Kompilierungszeit, wenn der Präprozessor einschaltet, haben Sie kein Glück.
quelle
strrchr
Antwort könnte plausibel zur Kompilierungszeit berechnet werden, obwohl dies natürlich immer noch nicht vom Präprozessor geschieht. Ich weiß nicht, ob gcc es tatsächlich tut, ich habe es nicht überprüft, aber ich bin mir ziemlich sicher, dass esstrlen
zur Kompilierungszeit aus String-Literalen berechnet .__FILE__
implizit durch aufgerufen wirdassert()
, kann dieses Leck ohne jede andere offensichtliche Handlung auftreten.__FILE__
selbst kann auch Dinge enthüllen, die der Kunde möglicherweise lieber nicht möchte. Die Verwendung von__FILE__
irgendwo überhaupt - unabhängig davon, ob er den vollständigen absoluten Pfadnamen oder nur den Basisnamen enthält - hat dieselben Probleme, auf die Sie hingewiesen haben. In dieser Situation muss die gesamte Ausgabe überprüft und eine spezielle API für die Ausgabe an Kunden eingeführt werden. Der Rest der Ausgabe sollte in / dev / NULL oder stdout ausgegeben und stderr sollte geschlossen werden. :-)Verwenden Sie die Funktion basename () oder unter Windows _splitpath () .
Versuchen Sie es auch
man 3 basename
in einer Shell.quelle
char file_copy[] = __FILE__; const char *filename = basename(__FILE__);
. Der Grund für die Kopie ist, dass der Basisname die Eingabezeichenfolge ändern kann. Sie müssen auch darauf achten, dass der Ergebniszeiger nur gut ist, bisbasename
er erneut aufgerufen wird. Dies bedeutet, dass es nicht threadsicher ist.basename
dass die daraus resultierende Eingabezeichenfolge tatsächlich nicht geändert wird__FILE__
, da die Eingabezeichenfolge/
am Ende keine hat und daher keine Änderungen erforderlich sind. Sie könnten also damit durchkommen, aber ich denke, wenn jemand das erste Mal siehtbasename
, sollte er es mit allen Einschränkungen sehen./
ihr Argument am Ende des Strings Mittel Basisnamen kann einen guten Grund haben , zu ändern.Wenn Sie
CMAKE
mit dem GNU-Compiler arbeitenglobal
, funktioniert diese Definition einwandfrei:quelle
Ich verwende seit Jahren dieselbe Lösung mit @Patricks Antwort .
Es gibt ein kleines Problem, wenn der vollständige Pfad eine Symbolverknüpfung enthält.
Bessere Lösung.
Warum sollte man das benutzen?
-Wno-builtin-macro-redefined
um die Compiler-Warnungen für die Neudefinition des__FILE__
Makros stummzuschalten.Das Entfernen des Projektpfads vom Dateipfad ist Ihre eigentliche Anforderung. Sie möchten nicht die Zeit verschwenden, um herauszufinden, wo sich eine
header.h
Datei befindet,src/foo/header.h
odersrc/bar/header.h
.Wir sollten das
__FILE__
Makro in dercmake
Konfigurationsdatei entfernen.Dieses Makro wird in den meisten vorhandenen Codes verwendet. Definieren Sie es einfach neu, um frei zu werden.
Compiler wie
gcc
definieren dieses Makro anhand der Befehlszeilenargumente vor. Und der vollständige Pfad wird inmakefile
s geschrieben, das von generiert wirdcmake
.Hardcode in
CMAKE_*_FLAGS
ist erforderlich.Es gibt einige Befehle zum Hinzufügen von Compileroptionen oder -definitionen in einer neueren Version, wie z . B.
add_definitions()
undadd_compile_definitions()
. Diese Befehle analysieren die make-Funktionen wiesubst
zuvor für Quelldateien. Das wollen wir nicht.Robuster Weg für
-Wno-builtin-macro-redefined
.quelle
__FILE__
mit Ihrer Definition eine Diagnose in einer Inline-Funktion erstellen, die in einer Header-Datei definiert ist, meldet die Laufzeitdiagnose den Namen der an den Compiler übergebenen Datei anstelle des Namens der Include-Datei, während die Zeilennummer dies tun würde Siehe die Include-Datei.#define LOG(fmt, args...) printf("%s " fmt, __FILE__, ##args)
. Wenn Sie dasLOG()
Makro verwenden, möchten Sie es nicht wirklichlog.h
in Nachrichten sehen. Schließlich wird das__FILE__
Makro in jeder C / Cpp-Datei (Kompilierungseinheit) anstelle der enthaltenen Dateien erweitert.Eine geringfügige Abweichung von dem, was @ red1ynx vorgeschlagen hat, wäre das Erstellen des folgenden Makros:
Fügen Sie in jeder Ihrer .c (pp) -Dateien Folgendes hinzu:
Dann können Sie sich beziehen
THIS_FILE_NAME
statt__FILE__
:Dies bedeutet, dass die Konstruktion einmal pro .c (pp) -Datei ausgeführt wird, anstatt jedes Mal, wenn auf das Makro verwiesen wird.
Es ist auf die Verwendung nur aus .c (pp) -Dateien beschränkt und kann aus Header-Dateien nicht verwendet werden.
quelle
Ich habe ein Makro erstellt
__FILENAME__
, das es vermeidet, jedes Mal den vollen Pfad zu schneiden. Das Problem besteht darin, den resultierenden Dateinamen in einer cpp-lokalen Variablen zu speichern.Dies kann einfach durch Definieren einer statischen globalen Variablen in der .h- Datei erfolgen. Diese Definition enthält separate und unabhängige Variablen in jeder CPP- Datei, die die .h- Datei enthält . Um ein Multithreading-Proof zu sein, lohnt es sich, die Variablen auch threadlokal (TLS) zu machen.
Eine Variable speichert den Dateinamen (verkleinert). Ein anderer enthält den nicht geschnittenen Wert,
__FILE__
der angegeben wurde. Die h-Datei:Das Makro selbst ruft eine Methode mit der gesamten Logik auf:
Und die Funktion wird folgendermaßen implementiert:
Das removePath () kann auf verschiedene Arten implementiert werden, aber das schnelle und einfache scheint mit strrchr zu sein:
quelle
Der aktuelle Clang-Compiler verfügt über ein
__FILE_NAME__
Makro (siehe hier ).quelle
Ich hoffe nur, das FILE-Makro ein wenig zu verbessern:
#define FILE (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
Dies fängt / und \, wie Czarek Tomczak es verlangt hat, und dies funktioniert großartig in meiner gemischten Umgebung.
quelle
FILE
ist eine wirklich schlechte Idee, wenn Sie einschließen<stdio.h>
.Versuchen
nach den include-Anweisungen in Ihre Quelldatei und fügen Sie hinzu
am Ende Ihrer Quelldatei.
quelle
push_macro
undpop_macro
sind nicht Standard. (gcc unterstützt sie aus Gründen der Kompatibilität mit Microsoft Windows-Compilern.) In jedem Fall macht es keinen Sinn, die Definition von zu verschieben und zu löschen__FILE__
. Der wiederhergestellte Wert wird ohnehin nach dem Ende der Quelldatei nicht mehr verwendet. Eine sauberere Möglichkeit, den Wert von zu ändern,__FILE__
ist#line __LINE__ "foobar.c"
Hier ist eine tragbare Funktion, die sowohl für Linux (Pfad '/') als auch für Windows (Mischung aus '\' und '/') funktioniert.
Kompiliert mit gcc, clang und vs.
Standardausgabe:
quelle
Hier ist die Lösung, die die Berechnung der Kompilierungszeit verwendet:
quelle
Wenn Sie auf dieser Seite nach einer Möglichkeit gesucht haben, den absoluten Quellpfad, der auf einen hässlichen Build-Speicherort verweist, aus der von Ihnen gelieferten Binärdatei zu entfernen, entspricht dies möglicherweise Ihren Anforderungen.
Obwohl dies nicht genau die Antwort liefert, die der Autor gewünscht hat , da es die Verwendung von CMake voraussetzt , kommt es ziemlich nahe. Schade, dass dies zuvor von niemandem erwähnt wurde, da es mir viel Zeit gespart hätte.
Wenn Sie die obige Variable auf setzen,
ON
wird ein Build-Befehl im folgenden Format generiert:Infolgedessen wird das
__FILE__
Makro in aufgelöst../../src/path/to/source.c
CMake-Dokumentation
Beachten Sie jedoch die Warnung auf der Dokumentationsseite:
Es ist nicht garantiert, dass es in allen Fällen funktioniert, aber es funktioniert in meinem - CMake 3.13 + gcc 4.5
quelle
Da Sie GCC verwenden, können Sie Vorteil nehmen von
und steuern Sie dann, wie Sie den Dateinamen anzeigen möchten, indem Sie die Darstellung der Quelldatei (vollständiger Pfad / relativer Pfad / Basisname) zur Kompilierungszeit ändern.
quelle
__FILE__
und__BASE_FILE__
jedoch zeigen beide den vollständigen Pfad zur Dateigcc /absolute/path/to/file.c
. Wenn Sie einen Weg finden, dieses Verhalten zu ändern (eine weitere Frage zu SO, lol?), Müssen Sie die Zeichenfolge zur Laufzeit nicht ändern__BASE_FILE__
(wie in den Dokumenten angegeben, wenn auch unklar) erzeugt den Namen der in der Befehlszeile angegebenen Datei , z. B.test.c
oder/tmp/test.c
abhängig davon, wie Sie den Compiler aufgerufen haben. Das ist genau das Gleiche wie__FILE__
, außer wenn Sie sich in einer Header-Datei befinden. In diesem Fall__FILE__
wird der Name der aktuellen Datei (z. B.foo.h
) erzeugt, während__BASE_FILE__
weiterhin produziert wirdtest.c
.Hier ist eine Lösung, die für Umgebungen funktioniert, in denen die Zeichenfolgenbibliothek nicht vorhanden ist (Linux-Kernel, eingebettete Systeme usw.):
Jetzt einfach
FILENAME
anstelle von verwenden__FILENAME__
. Ja, es ist immer noch eine Laufzeitsache, aber es funktioniert.quelle
quelle
Eine kurze, funktionierende Antwort für Windows und * nix:
quelle
std::max<const char*>
statt nurstd::max
?