wake-up-neo.com

Wie bekomme ich das Verzeichnis, aus dem ein Programm läuft?

Gibt es eine plattformagnostische und dateisystemagnostische Methode, um den vollständigen Pfad des Verzeichnisses zu ermitteln, in dem ein Programm mit C/C++ ausgeführt wird? Nicht mit dem aktuellen Arbeitsverzeichnis verwechseln. (Bitte schlagen Sie keine Bibliotheken vor, es sei denn, sie sind Standard wie clib oder STL.)

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

245
Ashwin Nanjappa

Hier finden Sie 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;
164
Mike

Wenn Sie das aktuelle Verzeichnis abrufen, wenn Ihr Programm zum ersten Mal gestartet wird, haben Sie das Verzeichnis, aus dem Ihr Programm gestartet wurde. Speichern Sie den Wert in einer Variablen und verweisen Sie darauf später in Ihrem Programm. Dies unterscheidet sich von dem Verzeichnis, in dem sich die aktuelle ausführbare Programmdatei befindet . Es ist nicht notwendigerweise dasselbe Verzeichnis; Wenn jemand das Programm über eine Eingabeaufforderung ausführt, wird das Programm ausgeführt von des aktuellen Eingabeverzeichnisses der Eingabeaufforderung, obwohl die Programmdatei an einem anderen Ort lebt.

getcwd ist eine POSIX-Funktion und wird von allen POSIX-kompatiblen Plattformen standardmäßig unterstützt. Sie müssen nichts Besonderes tun (abgesehen davon, dass Sie die richtigen Header unistd.h unter Unix und direct.h unter Windows verwenden).

Da Sie ein C-Programm erstellen, wird eine Verknüpfung mit der Standard-Laufzeitbibliothek hergestellt, die mit ALLEN Prozessen im System verknüpft ist (speziell hergestellte Ausnahmen werden vermieden). Diese Funktion ist standardmäßig enthalten. Das CRT wird niemals als externe Bibliothek betrachtet, da dies die standardkonforme Standardschnittstelle des Betriebssystems darstellt.

Unter Windows wurde die Funktion getcwd zugunsten von _getcwd aufgegeben. Ich denke, du könntest es auf diese Weise benutzen.

#include <stdio.h>  /* defines FILENAME_MAX */
#ifdef WINDOWS
    #include <direct.h>
    #define GetCurrentDir _getcwd
#else
    #include <unistd.h>
    #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);
159
computinglife

Dies ist aus dem cplusplus-Forum

Unter Windows:

#include <string>
#include <windows.h>

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

Unter Linux:

#include <string>
#include <limits.h>
#include <unistd.h>

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 );
}

Unter HP-UX:

#include <string>
#include <limits.h>
#define _PSTAT64
#include <sys/pstat.h>
#include <sys/types.h>
#include <unistd.h>

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 );
}
34
Octopus

Wenn Sie einen Standardweg ohne Bibliotheken wünschen: Nein. Das gesamte Konzept eines Verzeichnisses ist nicht im Standard enthalten.

Wenn Sie damit einverstanden sind, dass eine (tragbare) Abhängigkeit von einer nahezu standardmäßigen Bibliothek in Ordnung ist, verwenden Sie die Dateisystembibliothek von Boost und fragen Sie nach initial_path ()

IMHO ist so nah wie möglich, mit gutem Karma (Boost ist ein etablierter Satz hochwertiger Bibliotheken)

28
Thorsten79

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

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

In gcc (5.3+) zum Einschließen des Dateisystems müssen Sie Folgendes verwenden:

#include <experimental/filesystem>

und verknüpfen Sie Ihren Code mit dem Flag -lstdc++fs.

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

18
Marqin

Ich weiß, es ist sehr spät am Tag, um eine Antwort auf diese Frage zu werfen, 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 Ihrer CWD zu Ihrem bin-Ordner zu bekommen, sieht folgendermaßen aus:

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 einfach als Basis für Ihren relativen Pfad verwenden. Ich habe zum Beispiel diese Verzeichnisstruktur:

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

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

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

Ich habe diesen Ansatz unter Linux mit vollem Pfad, Alias ​​usw. ausprobiert und funktioniert problemlos.

HINWEIS:

Wenn Sie unter Windows arbeiten, sollten Sie ein '\' als Dateitrennzeichen verwenden, nicht '/'. Dies müssen Sie beispielsweise auch vermeiden:

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

Ich denke, dass dies funktionieren sollte, aber noch nicht getestet wurde, daher wäre ein Kommentar dankbar, wenn er funktioniert oder eine Korrektur, falls nicht. 

16
Sam Redway

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

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

Sie sollten auch festlegen, ob Sie das aktuelle Verzeichnis oder das Verzeichnis, in dem sich das Programmimage/die ausführbare Datei befindet, erstellen möchten. Wie es aussieht, ist Ihre Frage in diesem Punkt etwas unklar.

8
Michael Burr

Verketten Sie möglicherweise das aktuelle Arbeitsverzeichnis mit argv [0]? Ich bin mir nicht sicher, ob das unter Windows funktionieren würde, aber es funktioniert unter Linux.

Zum Beispiel:

#include <stdio.h>
#include <unistd.h>
#include <string.h>

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 ausgeführt, wird Folgendes ausgegeben:

jeremy @ jeremy-desktop: ~/Desktop $ ./test
/home/jeremy/Desktop/./test

7
Jeremy Ruten

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 Prozess könnte mit einem beliebigen Wert im Feld erstellt werden. 

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

Verwenden Sie unter Windows GetModuleFileName (), unter Linux die Dateien/dev/proc / procID / ...

6
eugensk00

Für Win32 sollte GetCurrentDirectory den Trick ausführen.

Unter Windows ist es am einfachsten, die _get_pgmptr-Funktion in stdlib.h zu verwenden, um einen Zeiger auf eine Zeichenfolge zu erhalten, die den absoluten Pfad zur ausführbaren Datei einschließlich des Namens der ausführbaren Dateien darstellt.

char* path;
_get_pgmptr(&path);
printf(path); // Example output: C:/Projects/Hello/World.exe
5
Adam Yaxley

Nur zum verspäteten Haufen hier ...

es gibt keine Standardlösung, da die Sprachen keine zugrundeliegenden Dateisysteme haben. Das Konzept eines verzeichnisbasierten Dateisystems liegt, wie andere schon sagten, außerhalb des Geltungsbereichs der c/c ++ - Sprachen.

darüber hinaus möchten Sie nicht das aktuelle Arbeitsverzeichnis, sondern das Verzeichnis, in dem das Programm ausgeführt wird. Dabei muss berücksichtigt werden, wie das Programm dorthin gelangt ist, d. Um das Verzeichnis zu erhalten, in dem ein Programm ausgeführt wird, müssen die Informationen, wie die Lösungen gezeigt haben, von den Prozesssteuerungsstrukturen des betreffenden Betriebssystems abgerufen werden. Dies ist die einzige Berechtigung für diese Frage. Per Definition handelt es sich also um eine betriebssystemspezifische Lösung.

3
Minok

Bei einem Windows-System an der Konsole können Sie den Befehl system (dir) verwenden. In der Konsole finden Sie Informationen zu Verzeichnis und usw. Lesen Sie den Befehl dir unter cmd. Aber für Unix-ähnliche Systeme weiß ich nicht ... Wenn dieser Befehl ausgeführt wird, lesen Sie den Befehl bash. ls zeigt das Verzeichnis nicht an ...

Beispiel:

int main()
{
    system("dir");
    system("pause"); //this wait for Enter-key-press;
    return 0;
}
3
Alexey1993
#include <windows.h>
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);
}
2
freezotic

Der Linux-Bash-Befehl which progname gibt einen Pfad zum Programm an.

Selbst wenn Sie den Befehl which innerhalb Ihres Programms ausgeben und die Ausgabe in eine tmp-Datei umleiten können und das Programm Diese tmp-Datei anschließend liest, wird Ihnen nicht mitgeteilt, ob dieses Programm das ausführende ist. Es sagt Ihnen nur, wo sich ein Programm mit diesem Namen befindet.

Es ist erforderlich, Ihre Prozess-ID-Nummer zu erhalten und den Pfad zu dem Namen zu analysieren 

In meinem Programm möchte ich wissen, ob das Programm im Bin-Verzeichnis des Benutzers oder in einem anderen Verzeichnis im Pfad Oder in/usr/bin ausgeführt wurde./usr/bin würde die unterstützte Version enthalten. Mein Gefühl ist, dass es in Linux die einzige tragbare Lösung gibt.

1

Für relative Pfade habe ich Folgendes getan. Ich bin mir des Alters dieser Frage bewusst, ich möchte lediglich eine einfachere Antwort beisteuern, die in den meisten Fällen funktioniert:

Angenommen, Sie haben einen solchen Pfad:

"path/to/file/folder"

Aus irgendeinem Grund funktionieren in Linux erstellte ausführbare Dateien, die in Eclipse erstellt wurden, gut damit. Windows wird jedoch sehr verwirrt, wenn ein derartiger Pfad zum Arbeiten angegeben wird!

Wie oben erwähnt, gibt es mehrere Möglichkeiten, den aktuellen Pfad zur ausführbaren Datei abzurufen, aber die einfachste Methode, die ich finde, wirkt in den meisten Fällen reizvoll, wenn Sie dies an die Vorderseite Ihres Pfads anfügen:

"./path/to/file/folder"

Wenn Sie einfach "./" hinzufügen, sollten Sie sich ordnen! :) Dann können Sie mit dem Laden eines beliebigen Verzeichnisses beginnen, solange es mit der ausführbaren Datei selbst ist.

BEARBEITEN: Dies funktioniert nicht, wenn Sie versuchen, die ausführbare Datei von code :: blocks zu starten, wenn dies die verwendete Entwicklungsumgebung ist, da code :: blocks aus irgendeinem Grund nicht richtig geladen wird: D

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

"resources/Example.data"

Wenn Sie Ihre App dann aus dem aktuellen Verzeichnis starten (oder in Windows eine Verknüpfung erstellen und das Arbeitsverzeichnis auf Ihr App-Verzeichnis festlegen), wird es wie folgt funktionieren .. Beachten Sie dies beim Debuggen von Problemen im Zusammenhang mit fehlenden Dateien Ressourcen-/Dateipfade. (Insbesondere bei IDEs, die beim Starten eines Build-Exes aus der IDE das falsche Arbeitsverzeichnis festlegen)

1
FuzzyQuills

Wie Minok erwähnt, gibt es keine solche Funktionalität, die im C-Standard oder im C++ - Standard spezifiziert ist. Dies wird als rein betriebssystemspezifisches Merkmal angesehen und ist beispielsweise im POSIX-Standard festgelegt.

Thorsten79 hat einen guten Vorschlag gemacht, es ist die Boost.Filesystem Bibliothek. Dies kann jedoch unpraktisch sein, wenn Sie für Ihr Programm keine binären Verknüpfungszeitabhängigkeiten benötigen.

Eine gute Alternative, die ich empfehlen würde, ist die Sammlung von 100% nur Kopfzeilen STLSoft C++ - BibliothekenMatthew Wilson (Autor von Büchern, die man über C++ lesen muss). Es gibt eine tragbare Fassade PlatformSTL ermöglicht den Zugriff auf systemspezifische APIs: WinSTL für Windows und UnixSTL unter Unix, sodass es sich um eine tragbare Lösung handelt. Alle systemspezifischen Elemente werden unter Verwendung von Merkmalen und Richtlinien spezifiziert, sodass es sich um ein erweiterbares Framework handelt. Natürlich gibt es eine Dateisystembibliothek.

0
mloskot

Die initial_path() von Boost Filesystem verhält sich wie die getcwd() von POSIX und tut nicht das, was Sie wollen, aber argv[0] sollte an einen der beiden angehängt werden.

Sie können feststellen, dass das Ergebnis nicht immer schön ist - Sie erhalten möglicherweise Dinge wie /foo/bar/../../baz/a.out oder /foo/bar//baz/a.out, aber ich glaube, dass es immer einen gültigen Pfad gibt, der die ausführbare Datei benennt (beachten Sie, dass aufeinander folgende Schrägstriche in einem Pfad auf einen Pfad reduziert werden).

Ich habe zuvor eine Lösung geschrieben, die envp (das dritte Argument für main(), das unter Linux funktionierte, aber unter Windows nicht funktionieren konnte). Daher empfehle ich im Wesentlichen dieselbe Lösung wie zuvor ein anderer, jedoch mit der zusätzlichen Erklärung, warum dies so ist eigentlich richtig, auch wenn die Ergebnisse nicht hübsch sind.

0
John Zwinck

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

Unter Windows können Sie _getcwd () verwenden, da die Verwendung von getcwd () nicht mehr empfohlen wird.

Wenn Standardbibliotheken für Sie Standard wären, hätte Boost :: das Dateisystem vorgeschlagen, aber die Pfadnormalisierung wurde scheinbar aus dem Vorschlag entfernt. Sie müssen möglicherweise warten, bis TR2 für eine vollständige Standardlösung verfügbar ist .

0
Fruny

Eine Bibliothekslösung (obwohl ich weiß, dass nicht danach gefragt wurde) . Falls Sie Qt verwenden: QCoreApplication::applicationDirPath()

0
Joachim

Verwenden Sie realpath() in stdlib.h wie folgt:

char *working_dir_path = realpath(".", NULL);
0
Manabu Nakazawa

Arbeitet mit C++ 11, experimentellem Dateisystem und C++ 14-C++ 17 sowie offiziellem Dateisystem.

application.h:

#pragma once

//
// https://en.cppreference.com/w/User:D41D8CD98F/feature_testing_macros
//
#ifdef __cpp_lib_filesystem
#include <filesystem>
#else
#include <experimental/filesystem>

namespace std {
    namespace filesystem = experimental::filesystem;
}
#endif

std::filesystem::path getexepath();

application.cpp:

#include "application.h"
#ifdef _WIN32
#include <windows.h>    //GetModuleFileNameW
#else
#include <limits.h>
#include <unistd.h>     //readlink
#endif

std::filesystem::path getexepath()
{
#ifdef _WIN32
    wchar_t path[MAX_PATH] = { 0 };
    GetModuleFileNameW(NULL, path, MAX_PATH);
    return path;
#else
    char result[PATH_MAX];
    ssize_t count = readlink("/proc/self/exe", result, PATH_MAX);
    return std::string(result, (count > 0) ? count : 0);
#endif
}
0
TarmoPikaro