Wie bekomme ich das Verzeichnis, von dem ein Programm ausgeführt wird?

Gibt es eine plattformunabhängige und filesystem-agnostische Methode, um den vollständigen Pfad des Verzeichnisses zu erhalten, in dem ein Programm mit C / C ++ läuft? Nicht zu verwechseln mit dem aktuellen Arbeitsverzeichnis. (Bitte schlagen Sie keine Bibliotheken vor, es sei denn, es handelt sich um Standardclips wie CLL oder STL.)

(Wenn es keine plattform / Dateisystem-unabhängige Methode gibt, sind auch Vorschläge, die für bestimmte Dateisysteme in Windows und Linux funktionieren, willkommen.)

Hier ist Code, um den vollständigen Pfad zur ausführenden App zu erhalten:

Windows:

 int bytes = GetModuleFileName(NULL, pBuf, len); if(bytes == 0) return -1; else return bytes; 

Linux:

 char szTmp[32]; sprintf(szTmp, "/proc/%d/exe", getpid()); int bytes = MIN(readlink(szTmp, pBuf, len), len - 1); if(bytes >= 0) pBuf[bytes] = '\0'; return bytes; 

Wenn Sie das aktuelle Verzeichnis aufrufen, wenn Ihr Programm zum ersten Mal gestartet wird, haben Sie tatsächlich das Verzeichnis, von dem aus Ihr Programm gestartet wurde. Speichern Sie den Wert in einer Variablen und beziehen Sie sich später darauf in Ihrem Programm. Dies unterscheidet sich von dem Verzeichnis, in dem sich die aktuelle ausführbare Programmdatei befindet . Es ist nicht unbedingt das gleiche Verzeichnis; Wenn jemand das Programm über eine Eingabeaufforderung ausführt, wird das Programm über das aktuelle Arbeitsverzeichnis der Eingabeaufforderung ausgeführt, obwohl die Programmdatei an einem anderen Ort gespeichert ist.

getcwd ist eine POSIX-function und wird von allen POSIX-kompatiblen Plattformen sofort unterstützt. Sie müssen nichts Besonderes machen (abgesehen von den rechten Kopfzeilen unistd.h unter Unix und direct.h unter Windows).

Da Sie ein C-Programm erstellen, wird es mit der Standard-c-Laufzeitbibliothek verknüpft, die mit ALLEN processen im System verknüpft ist (speziell gestaltete Ausnahmen werden vermieden) und es wird diese function standardmäßig enthalten. Der CRT wird niemals als externe Bibliothek betrachtet, da dies die grundlegende standardkonforme Schnittstelle zum Betriebssystem bereitstellt.

Unter Windows ist die function getcwd zugunsten von _getcwd veraltet. Ich denke du könntest es auf diese Weise benutzen.

 #include  /* defines FILENAME_MAX */ #ifdef WINDOWS #include  #define GetCurrentDir _getcwd #else #include  #define GetCurrentDir getcwd #endif char cCurrentPath[FILENAME_MAX]; if (!GetCurrentDir(cCurrentPath, sizeof(cCurrentPath))) { return errno; } cCurrentPath[sizeof(cCurrentPath) - 1] = '\0'; /* not really required */ printf ("The current working directory is %s", cCurrentPath); 

Dies ist aus dem cplusplus-Forum

An Fenstern:

 #include  #include  std::string getexepath() { char result[ MAX_PATH ]; return std::string( result, GetModuleFileName( NULL, result, MAX_PATH ) ); } 

Unter Linux:

 #include  #include  #include  std::string getexepath() { char result[ PATH_MAX ]; ssize_t count = readlink( "/proc/self/exe", result, PATH_MAX ); return std::string( result, (count > 0) ? count : 0 ); } 

Auf HP-UX:

 #include  #include  #define _PSTAT64 #include  #include  #include  std::string getexepath() { char result[ PATH_MAX ]; struct pst_status ps; if (pstat_getproc( &ps, sizeof( ps ), 0, getpid() ) < 0) return std::string(); if (pstat_getpathname( result, PATH_MAX, &ps.pst_fid_text ) < 0) return std::string(); return std::string( result ); } 

Wenn Sie einen Standardweg ohne Bibliotheken wollen: Nein. Das ganze Konzept eines Verzeichnisses ist im Standard nicht enthalten.

Wenn Sie zustimmen, dass eine (portable) Abhängigkeit von einer fast -Standard- Bibliothek in Ordnung ist: Verwenden Sie die Dateisystem-Bibliothek von Boost und fragen Sie nach initial_path () .

IMHO, das ist so nah wie Sie können, mit gutem Karma (Boost ist eine gut etablierte hochwertige Reihe von Bibliotheken)

Dateisystem-TS ist jetzt ein Standard (und wird von gcc 5.3+ und clang 3.9+ unterstützt), so dass Sie die current_path() -function verwenden können:

 std::string path = std::experimental::filesystem::current_path(); 

In gcc (5.3+) zum Einbinden von Dateisystem benötigen Sie:

 #include  

und verlinke deinen Code mit -lstdc++fs flag.

Wenn Sie das Dateisystem mit Microsoft Visual Studio verwenden möchten, lesen Sie dies .

Ich weiß, dass es sehr spät am Tag ist, um eine Antwort zu diesem Thema zu casting, aber ich fand, dass keine der Antworten für mich so nützlich war wie meine eigene Lösung. Eine sehr einfache Möglichkeit, den Pfad von Ihrem CWD zu Ihrem bin-Ordner zu erhalten, ist wie folgt:

 int main(int argc, char* argv[]) { std::string argv_str(argv[0]); std::string base = argv_str.substr(0, argv_str.find_last_of("/")); } 

Sie können dies jetzt als Basis für Ihren relativen Pfad verwenden. So habe ich zum Beispiel diese Verzeichnisstruktur:

 main ----> test ----> src ----> bin 

und ich möchte meinen Quellcode zu bin kompilieren und ein Protokoll schreiben, um zu testen, ich kann nur diese Zeile zu meinem Code hinzufügen.

 std::string pathToWrite = base + "/../test/test.log"; 

Ich habe diesen Ansatz unter Linux mit vollem Pfad, Alias ​​usw. versucht und es funktioniert gut.

HINWEIS:

Wenn Sie Windows verwenden, sollten Sie ein ‘\’ als Dateitrennzeichen und nicht ‘/’ verwenden. Sie müssen dies auch zum Beispiel entkommen:

 std::string base = argv[0].substr(0, argv[0].find_last_of("\\")); 

Ich denke, das sollte funktionieren, aber nicht getestet haben, so würde Kommentar geschätzt werden, wenn es funktioniert oder eine Reparatur, wenn nicht.

Nein, es gibt keinen Standardweg. Ich glaube, dass die C / C ++ – Standards nicht einmal die Existenz von Verzeichnissen (oder anderen Dateisystem-Organisationen) berücksichtigen.

Unter Windows gibt GetModuleFileName () den vollständigen Pfad zur ausführbaren Datei des aktuellen processes zurück, wenn der Parameter hModule auf NULL gesetzt ist . Ich kann nicht mit Linux helfen.

Außerdem sollten Sie klären, ob Sie das aktuelle Verzeichnis oder das Verzeichnis, in dem sich das Programm image / executable befindet, wünschen. Wie es aussieht, ist Ihre Frage in diesem Punkt ein wenig mehrdeutig.

Vielleicht das aktuelle Arbeitsverzeichnis mit argv [0] verketten? Ich bin mir nicht sicher, ob das in Windows funktionieren würde, aber es funktioniert in Linux.

Beispielsweise:

 #include  #include  #include  int main(int argc, char **argv) { char the_path[256]; getcwd(the_path, 255); strcat(the_path, "/"); strcat(the_path, argv[0]); printf("%s\n", the_path); return 0; } 

Wenn es ausgeführt wird, gibt es aus:

Jeremy @ Jeremy-Desktop: ~ / Desktop $. / Test
/home/jeremy/Desktop/./test

Sie können argv [0] nicht für diesen Zweck verwenden, normalerweise enthält es den vollständigen Pfad zur ausführbaren Datei, aber nicht unbedingt – der process könnte mit einem beliebigen Wert im Feld erstellt werden.

Auch das aktuelle Verzeichnis und das Verzeichnis mit der ausführbaren Datei sind zwei verschiedene Dinge, also wird getcwd () auch Ihnen nicht helfen.

Unter Windows verwenden Sie GetModuleFileName (), unter Linux lesen Sie / dev / proc / procID / .. Dateien.

Für Win32 sollte GetCurrentDirectory den Trick machen.

Für Windows-System an der Konsole können Sie den Befehl system ( dir ) verwenden. Und die Konsole gibt Ihnen Informationen über das Verzeichnis usw. Lesen Sie über den Befehl dir bei cmd . Aber für Unix-ähnliche Systeme, weiß ich nicht … Wenn dieser Befehl ausgeführt wird, lesen Sie den Befehl bash. ls zeigt Verzeichnis nicht an …

Beispiel:

 int main() { system("dir"); system("pause"); //this wait for Enter-key-press; return 0; } 

Nur um später hier anzuhäufen, …

Es gibt keine Standardlösung, da die Sprachen nichts mit den zugrundeliegenden Dateisystemen zu tun haben. Wie andere bereits gesagt haben, liegt das Konzept eines verzeichnisbasierten Dateisystems außerhalb des Geltungsbereichs der c / c ++ – Sprachen.

Darüber hinaus wollen Sie nicht das aktuelle Arbeitsverzeichnis, sondern das Verzeichnis, in dem das Programm läuft, welches berücksichtigen muss, wie das Programm dorthin gelangt ist, wo es ist – dh wurde es als neuer process über eine Verzweigung usw. erzeugt. Um das Verzeichnis zu erhalten, in dem ein Programm ausgeführt wird, müssen Sie, wie die Lösungen gezeigt haben, diese Informationen von den processsteuerungsstrukturen des betreffenden Betriebssystems abrufen. Dies ist die einzige Autorität in dieser Frage. Daher ist es definitionsgemäß eine OS-spezifische Lösung.

Unter Windows ist es am einfachsten, die function _get_pgmptr in stdlib.h zu verwenden, um einen pointers auf eine Zeichenfolge _get_pgmptr die den absoluten Pfad zur ausführbaren Datei darstellt, einschließlich des ausführbaren _get_pgmptr .

 char* path; _get_pgmptr(&path); printf(path); // Example output: C:/Projects/Hello/World.exe 
 #include  using namespace std; // The directory path returned by native GetCurrentDirectory() no end backslash string getCurrentDirectoryOnWindows() { const unsigned long maxDir = 260; char currentDir[maxDir]; GetCurrentDirectory(maxDir, currentDir); return string(currentDir); } 

Der Linux-Bash-Befehl, welcher einen Programmpfad meldet.

Selbst wenn man den Befehl in seinem Programm ausgeben und die Ausgabe in eine tmp-Datei leiten könnte und das Programm diese tmp-Datei liest, wird es Ihnen nicht sagen, ob dieses Programm ausgeführt wird. Es sagt Ihnen nur, wo sich ein Programm mit diesem Namen befindet.

Was benötigt wird, ist, Ihre process-ID-Nummer zu erhalten und den Pfad zum Namen auszuwerten

In meinem Programm möchte ich wissen, ob das Programm aus dem Verzeichnis bin des Benutzers oder aus einem anderen im Pfad oder aus / usr / bin ausgeführt wurde. / usr / bin würde die unterstützte Version enthalten. Mein Gefühl ist, dass in Linux die eine Lösung tragbar ist.

Für relative Pfade, hier ist, was ich getan habe. Ich kenne das Alter dieser Frage, ich möchte einfach eine einfachere Antwort liefern, die in den meisten Fällen funktioniert:

Angenommen, Sie haben einen Pfad wie diesen:

 "path/to/file/folder" 

Aus irgendeinem Grund funktionieren Linux-basierte ausführbare Dateien, die in Eclipse gemacht werden, gut damit. Allerdings wird Windows sehr verwirrt, wenn man einen solchen Pfad benutzt!

Wie oben erwähnt, gibt es mehrere Möglichkeiten, um den aktuellen Pfad zur ausführbaren Datei zu erhalten, aber der einfachste Weg, den ich finde, wirkt in den meisten Fällen charmant, wenn Sie diesen an die FRONT Ihres Pfades anhängen:

 "./path/to/file/folder" 

Wenn Sie einfach “./” hinzufügen, sollten Sie sortiert werden! 🙂 Dann können Sie beginnen, von dem gewünschten Verzeichnis zu laden, solange es mit der ausführbaren Datei selbst ist.

EDIT: Das wird nicht funktionieren, wenn Sie versuchen, die ausführbare Datei von code :: blocks zu starten, wenn das die Entwicklungsumgebung ist, die verwendet wird, da code :: blocks Sachen nicht lädt, richtig …: D

EDIT2: Einige neue Dinge, die ich gefunden habe, ist, dass, wenn Sie einen statischen Pfad wie diesen in Ihrem Code angeben (Angenommen, Example.data ist etwas, das Sie laden müssen):

 "resources/Example.data" 

Wenn Sie dann Ihre App aus dem aktuellen Verzeichnis starten (oder in Windows eine Verknüpfung erstellen und das Arbeitsverzeichnis auf Ihr Anwendungsverzeichnis setzen), funktioniert es so. Beachten Sie dies beim Debuggen von Problemen mit fehlenden Ressourcen- / Dateipfaden. (Vor allem in IDEs, die beim Start einer Build-Exe aus der IDE das falsche Arbeitsverzeichnis setzen)

Auf POSIX-Plattformen können Sie getcwd () verwenden .

Unter Windows können Sie _getcwd () verwenden , da die Verwendung von getcwd () veraltet ist.

Wenn Boost für Standardbibliotheken Standard genug für Sie wäre, hätte ich Boost :: filesystem vorgeschlagen, aber sie scheinen die Pfadnormierung aus dem Angebot entfernt zu haben. Möglicherweise müssen Sie warten, bis TR2 für eine vollständige Standardlösung verfügbar ist .

Boost Filesystem’s initial_path() verhält sich wie POSIX’s getcwd() , und keiner tut was Sie wollen, aber das Anhängen von argv[0] an einen von beiden sollte es tun.

Sie werden bemerken, dass das Ergebnis nicht immer schön ist – Sie können Dinge wie /foo/bar/../../baz/a.out oder /foo/bar//baz/a.out , aber ich glaube das es führt immer zu einem gültigen Pfad, der die ausführbare Datei benennt (beachten Sie, dass aufeinander folgende Schrägstriche in einem Pfad auf eins reduziert werden).

Ich schrieb zuvor eine Lösung mit envp (dem dritten Argument von main() das unter Linux funktionierte, aber unter Windows nicht praktikabel schien. Daher empfehle ich im Wesentlichen die gleiche Lösung wie zuvor jemand, aber mit der zusätzlichen Erklärung warum es ist tatsächlich korrekt, auch wenn die Ergebnisse nicht schön sind.

Wie von Minok erwähnt, gibt es keine solche functionalität, die im C-Standard oder C ++ – Standard spezifiziert ist. Dies wird als reines Betriebssystem-spezifisches Merkmal betrachtet und beispielsweise im POSIX-Standard spezifiziert.

Thorsten79 hat einen guten Vorschlag gemacht, es ist Boost.Filesystem Bibliothek. Es kann jedoch unbequem sein, wenn Sie für Ihr Programm keine Verknüpfungszeitabhängigkeiten in binärer Form haben möchten.

Eine gute Alternative, die ich empfehlen würde, ist die Sammlung von 100% Header-only STLSoft C ++ Bibliotheken Matthew Wilson (Autor von Must-Read-Bücher über C ++). Es gibt portable Fassade PlatformSTL ermöglicht den Zugriff auf systemspezifische API: WinSTL für Windows und UnixSTL unter Unix, so ist es portable Lösung. Alle systemspezifischen Elemente werden unter Verwendung von Merkmalen und Richtlinien spezifiziert, so dass es sich um ein erweiterbares Framework handelt. Es gibt natürlich eine Dateisystembibliothek.

Eine Bibliothekslösung (obwohl ich weiß, dass dies nicht verlangt wurde). Wenn Sie Qt verwenden: QCoreApplication::applicationDirPath()