Wie erhalte ich das Verzeichnis, aus dem ein Programm ausgeführt wird?

269

Gibt es eine plattformunabhängige und eine dateisystemunabhängige Methode, um den vollständigen Pfad des Verzeichnisses abzurufen, aus dem ein Programm mit C / C ++ ausgeführt wird? Nicht zu verwechseln mit dem aktuellen Arbeitsverzeichnis. (Bitte schlagen Sie keine Bibliotheken vor, es sei denn, es handelt sich um Standardbibliotheken wie clib oder STL.)

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

Ashwin Nanjappa
quelle
@ Chakrit: Das wäre toll. (Obwohl dieses Problem normalerweise nicht unter Windows
auftritt
2
Wenn Sie den Pfad nicht zuverlässig extrahieren können argv[0], ist die Technik sehr betriebssystemabhängig.
David R Tribble
1
Zur Verdeutlichung: Das 'aktuelle Verzeichnis' oder 'das Verzeichnis, aus dem das Programm ausgeführt wird' (in der Terminologie der Frage) ist das Verzeichnis, in dem sich die Bilddatei des Programms (~ .exe-Datei) befindet, und Das 'aktuelle Arbeitsverzeichnis ' ist das Verzeichnis, das automatisch vervollständigt wird, wenn das Programm relative Pfade verwendet.
Colemik
3
Wenn Sie dies #include <windows.h>tun, fügt Windows automatisch einen char*in den ausführbaren Pfad ein _pgmptr. Sie müssen keine zusätzlichen Funktionen aufrufen oder Junk annehmen, wenn Sie nur unter Windows arbeiten.
Rsethc
1
Obwohl der Kommentar von vor drei Jahren stammt, möchte ich den Kommentar von rsethc über erweitern _pgmptr. In der MSDN-Dokumentation wird angegeben, dass die Variablen _pgmptrund _wpgmptrveraltet sind. Verwenden Sie stattdessen die Funktion _get_pgmptr(char**)oder _get_wpgmptr(wchar_t**). MSDN
Hydranix

Antworten:

181

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

Windows:

int bytes = GetModuleFileName(NULL, pBuf, len);
return bytes ? bytes : -1;

Linux:

int bytes = MIN(readlink("/proc/self/exe", pBuf, len), len - 1);
if(bytes >= 0)
    pBuf[bytes] = '\0';
return bytes;
Deduplikator
quelle
3
Ich denke, dies ist die einzige Antwort hier, die die Frage beantwortet, und zwar sowohl für Windows als auch für Linux. Gut gemacht.
Frank Szczerba
6
Boo für / proc / pid / exe - Wird unter OS X aus irgendeinem Grund nicht unterstützt.
Chris Lutz
24
Wenn ich Code sehe, der einen /procTeil von mir ansieht , stirbt er ein wenig. Die ganze Welt ist nicht Linux, und selbst auf dieser einen Plattform /procsollte davon ausgegangen werden, dass sie von Version zu Version, von Bogen zu Bogen usw.
geändert werden kann
4
Wenn sie unter Linux mit einem Alias-Befehl gestartet werden, ist argv [0] der "Name des Befehls" oder erweitert?
Andy Dent
20
Wie wäre es mit hinzufügen char pBuf[256]; size_t len = sizeof(pBuf);, um die Lösung klarer zu machen.
charles.cc.hsu
166

Wenn Sie das aktuelle Verzeichnis beim ersten Start Ihres Programms abrufen, haben Sie effektiv das Verzeichnis, aus dem Ihr Programm gestartet wurde. Speichern Sie den Wert in einer Variablen und beziehen Sie sich später in Ihrem Programm darauf. Dies unterscheidet sich von dem Verzeichnis, in dem sich die aktuelle ausführbare Programmdatei befindet . Es ist nicht unbedingt dasselbe Verzeichnis. Wenn jemand das Programm über eine Eingabeaufforderung ausführt, wird das Programm aus dem aktuellen Arbeitsverzeichnis der Eingabeaufforderung ausgeführt, obwohl sich die Programmdatei an einer anderen Stelle befindet.

getcwd ist eine POSIX-Funktion und wird von allen POSIX-kompatiblen Plattformen sofort unterstützt. Sie müssten nichts Besonderes tun (außer die richtigen Header unistd.h unter Unix und direct.h unter Windows einzuschließen).

Da Sie ein C-Programm erstellen, wird es mit der Standard-C-Laufzeitbibliothek verknüpft, mit der ALLE Prozesse im System verknüpft sind (speziell gestaltete Ausnahmen werden vermieden), und diese Funktion wird standardmäßig enthalten. Die CRT wird niemals als externe Bibliothek betrachtet, da dies die grundlegende standardkonforme Schnittstelle zum Betriebssystem darstellt.

Unter Windows wurde die Funktion getcwd zugunsten von _getcwd nicht mehr unterstützt. Ich denke, Sie könnten es auf diese Weise verwenden.

#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);
Computerleben
quelle
44
Gute Antwort, aber ich dachte, "aktuelles Arbeitsverzeichnis" sei nicht das, was man wollte.
Michael Burr
4
Sie sollten hinzufügen, dass selbst wenn einige Dokumentationen besagen, dass cCurrentpath null sein kann und von getcwd zugewiesen wird, getcwd unter Mac OS nichts zuzuweisen scheint und Ihr Programm leise abstürzt
Janusz
4
Es gibt einen kleinen Fehler, aber leider kann ich ihn noch nicht bearbeiten. Zeile 10: cCurrentpath: sollte cCurrentPath sein
Lipis
8
IMO unter Windows sollten die von POSIXy benannten Funktionen (von denen einige mit Unterstrichen beginnen) generell vermieden werden. Sie sind nicht die echten Windows-APIs, sondern die CRT. Die Windows-API, die Sie verwenden möchten, ist GetCurrentDirectory (). msdn.microsoft.com/en-us/library/aa364934(VS.85).aspx
asveikau
6
Mikes Antwort ist richtig. Das "aktuelle Verzeichnis" ist nicht immer dasselbe wie das Verzeichnis, aus dem die Binärdatei ausgeführt wird. Wenn eine App beispielsweise als Dienst unter Windows ausgeführt wird, lautet das aktuelle Verzeichnis wahrscheinlich C: \ Windows \ System32, während das Binärverzeichnis unterschiedlich ist.
Lucky Luke
42

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 );
}
Tintenfisch
quelle
1
Diese Windows-Lösung verarbeitet keine Nicht-ANSI-Zeichen im Pfad. Sie sollten wahrscheinlich GetModuleFileNameW verwenden und es explizit in UTF-8 konvertieren (achten Sie darauf, es zurück zu konvertieren, wenn Sie einen Dateisystembefehl ausgeben müssen).
Adrian McCarthy
3
Bei der Windows-Lösung wird error: cannot convert 'char*' to 'LPWCH {aka wchar_t*}' for argument '2' to 'DWORD GetModuleFileNameW(HMODULE, LPWCH, DWORD)'beim Kompilieren mit MinGW der Fehler angezeigt.
HelloGoodbye
2
@Adrian, ich bin im Allgemeinen kein Windows-Programmierer, aber gibt es keine DEFINE oder eine Möglichkeit, Ihren Compiler anzuweisen, die _W () -Funktion von Funktionen automatisch zu verwenden?
Octopus
1
@Octopus: Um die Wide Calls verwenden zu können, müssen Sie WCHAR (anstelle von char) und std :: wstring (anstelle von std :: string) verwenden.
Adrian McCarthy
29

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 dem initial_path () .

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

Thorsten79
quelle
8
Aus den Boost-Dokumenten: template <class Path> const Path & initial_path (); Rückgabe: current_path () zum Zeitpunkt der Eingabe von main (). Und current_path () ist 'wie von POSIX getcwd ()'. Dies hat der Fragesteller nicht verlangt.
Jonathan Leffler
Wie kommentiert, gibt dies den Pfad an, von dem aus die Binärdatei aufgerufen wurde, nicht den Pfad zur Binärdatei ... da sie von einem anderen Ordner aus gestartet werden könnte.
jpo38
21

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

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

In gcc (5.3+) müssen Sie Folgendes verwenden, um das Dateisystem einzuschließen:

#include <experimental/filesystem>

und verknüpfe deinen Code mit -lstdc++fsflag.

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

Marqin
quelle
6
Über den referenzierten Link 1-2) Returns the absolute path of the current working directory, obtained as if by POSIX getcwd. (2) returns path() if error occurs. Downvoted, da das OP speziell nach dem aktuellen Pfad der ausführbaren Datei und nicht nach dem aktuellen Arbeitsverzeichnis fragt.
S. Saad
20

Ich weiß, dass es sehr spät am Tag ist, eine Antwort auf diese Frage zu geben, aber ich fand, dass keine der Antworten für mich so nützlich war wie meine eigene Lösung. Ein sehr einfacher Weg, um den Pfad von Ihrem CWD zu Ihrem bin-Ordner zu erhalten, ist folgender:

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. So habe ich zum Beispiel diese Verzeichnisstruktur:

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

und ich möchte meinen Quellcode in bin kompilieren und ein Protokoll zum Testen schreiben. Ich kann diese Zeile einfach zu meinem Code hinzufügen.

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

Ich habe diesen Ansatz unter Linux mit vollständigem Pfad, Alias ​​usw. ausprobiert und er funktioniert einwandfrei.

HINWEIS:

Wenn Sie unter Windows arbeiten, sollten Sie ein '\' als Dateitrennzeichen verwenden, nicht '/'. Sie müssen sich auch dem entziehen, zum Beispiel:

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

Ich denke, dies sollte funktionieren, wurde aber nicht getestet. Daher wäre ein Kommentar willkommen, wenn es funktioniert, oder ein Fix, wenn nicht.

Sam Redway
quelle
Ja, es funktioniert auch unter Windows. Ich denke, das ist die beste Lösung. Soweit ich weiß, behält argv [0] immer den Pfad zur ausführbaren Datei.
Wodzu
4
argv[0]ist eine sehr schöne Idee, aber leider bekomme ich unter Linux "./my_executable_name" oder "./make/my_executable_name". Grundsätzlich hängt es völlig davon ab, wie ich es
starte
@ Xeverous: na und? Wenn ich einige Dateien zu meiner ausführbaren Datei habe, die geöffnet werden müssen, sollte in Ihren Fällen ab "./" oder "./make/" funktionieren. "." ist das aktuelle Arbeitsverzeichnis, und argv [0] gibt Ihnen den relativen Pfad zur ausführbaren Datei von dort an, genau das, was das OP wollen sollte. Das ist auf jeden Fall genau das, was ich brauche.
Nilo
9

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 auf NULL gesetzt ist . Ich kann nicht mit Linux helfen.

Außerdem sollten Sie klarstellen, ob Sie das aktuelle Verzeichnis oder das Verzeichnis möchten, in dem sich das Programmabbild / die ausführbare Datei befindet. Aus heutiger Sicht ist Ihre Frage in diesem Punkt etwas mehrdeutig.

Michael Burr
quelle
9

Unter Windows besteht die einfachste Möglichkeit darin, mit der _get_pgmptrFunktion in stdlib.heinen Zeiger auf eine Zeichenfolge abzurufen, die den absoluten Pfad zur ausführbaren Datei einschließlich des Namens der ausführbaren Datei darstellt.

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

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

Beispielsweise:

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

Beim Ausführen wird Folgendes ausgegeben:

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

Jeremy Ruten
quelle
Sie müssen überprüfen, ob in argv [0] ein absoluter Pfad angegeben ist. Was aber noch wichtiger ist, wenn sich das Bild über den PFAD befindet? Füllt Linux den vollständigen Pfad aus oder nur, was in der Befehlszeile steht?
Michael Burr
Wie Mike B betonte, ist dies eine nicht allgemeine Lösung. Es funktioniert nur unter sehr begrenzten Umständen. Grundsätzlich nur, wenn Sie den Befehl mit einem relativen Pfadnamen ausführen - und es ist nicht allzu elegant, wenn Sie ../../../bin/progname anstelle von ./test ausführen
Jonathan Leffler
Wenn Sie einen möglichen relativen Pfad von argv [0] im Vergleich zum aktuellen Verzeichnis auflösen (da argv [0] "../../myprogram.exe" sein könnte), ist dies wahrscheinlich der sicherste Weg, um die Frage zu beantworten. Es wird immer funktionieren und ist portabel (es funktioniert sogar auf Android!).
jpo38
7

Für Win32 sollte GetCurrentDirectory den Trick machen.

Torbjörn Gyllebring
quelle
Es gibt großen Fang mit dieser Funktion : Multithreaded - Anwendungen und Shared Library Code sollte nicht die GetCurrentDirectory Funktion verwenden und soll mit relativen Pfadnamen zu vermeiden . Wenn Sie mit dieser Annahme arbeiten können, ist dies die beste Lösung.
McLeary
6

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 kann 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, sodass getcwd () Ihnen auch nicht hilft.

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

Eugensk
quelle
3

Nur um sich hier verspätet anzuhäufen, ...

Es gibt keine Standardlösung, da die Sprachen unabhängig von den zugrunde liegenden Dateisystemen sind. Wie andere bereits gesagt haben, liegt das Konzept eines verzeichnisbasierten Dateisystems außerhalb des Bereichs 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 dort angekommen ist, wo es sich befindet - dh, es wurde als neuer Prozess über eine Verzweigung usw. erzeugt. Um das Verzeichnis abzurufen, in dem ein Programm ausgeführt wird, müssen Sie, wie die Lösungen gezeigt haben, diese Informationen aus den Prozesssteuerungsstrukturen des betreffenden Betriebssystems abrufen. Dies ist die einzige Berechtigung für diese Frage. Somit ist es per Definition eine betriebssystemspezifische Lösung.

Minok
quelle
3

Für Windows-Systeme an der Konsole können Sie den dirBefehl system ( ) verwenden. Die Konsole bietet Informationen zu Verzeichnissen usw. Weitere Informationen zum dirBefehl finden Sie unter cmd. Aber für Unix-ähnliche Systeme weiß ich nicht ... Wenn dieser Befehl ausgeführt wird, lesen Sie den Befehl bash. lszeigt kein Verzeichnis an ...

Beispiel:

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

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 Pfadnormalisierung aus dem Vorschlag entfernt zu haben. Möglicherweise müssen Sie warten, bis TR2 für eine vollständige Standardlösung verfügbar ist .

Fruny
quelle
10
getcwd () macht nicht das, was der Fragesteller gefragt hat.
Jonathan Leffler
Ist es nicht so, dass die akzeptierte Antwort getcwd () verwendet, oder verstehe ich nicht nur?
Sнаđошƒаӽ
Ich habe gestimmt, weil Sie derjenige sind, der zuerst die richtige Antwort erhalten hat.
Arnaud
Diese Antwort versucht nicht einmal, die Frage zu beantworten. Schade beim Schreiben.
HelloWorld
1

Für relative Pfade habe ich Folgendes getan. Ich bin mir des Alters dieser Frage bewusst und 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 in Eclipse erstellte Linux-erstellte ausführbare Dateien problemlos. Windows wird jedoch sehr verwirrt, wenn ein Pfad wie dieser angegeben wird, mit dem gearbeitet werden kann!

Wie oben erwähnt, gibt es verschiedene Möglichkeiten, um den aktuellen Pfad zur ausführbaren Datei abzurufen. Der einfachste Weg, den ich finde, funktioniert jedoch in den meisten Fällen, wenn Sie ihn an die Vorderseite Ihres Pfads anhängen:

"./path/to/file/folder"

Wenn Sie nur "./" hinzufügen, werden Sie sortiert! :) Dann können Sie mit dem Laden aus einem beliebigen Verzeichnis beginnen, solange es sich um die ausführbare Datei selbst handelt.

BEARBEITEN: Dies funktioniert nicht, wenn Sie versuchen, die ausführbare Datei aus Code :: -Blöcken zu starten, wenn dies die verwendete Entwicklungsumgebung ist. Aus irgendeinem Grund werden Code :: -Blöcke nicht richtig geladen ...: D.

EDIT2: Einige neue Dinge, die ich gefunden habe, sind: Wenn Sie einen statischen Pfad wie diesen in Ihrem Code angeben (Angenommen, Example.data müssen geladen werden):

"resources/Example.data"

Wenn Sie dann Ihre App aus dem tatsächlichen Verzeichnis starten (oder unter Windows eine Verknüpfung erstellen und das Arbeitsverzeichnis auf Ihr App-Verzeichnis festlegen), funktioniert dies folgendermaßen. Beachten Sie dies beim Debuggen von Problemen im Zusammenhang mit fehlenden Ressourcen- / Dateipfaden. (Insbesondere in IDEs, die beim Starten einer Build-Exe von der IDE das falsche Arbeitsverzeichnis festlegen)

FuzzyQuills
quelle
1

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

Joachim
quelle
1

Nur meine zwei Cent, aber funktioniert der folgende Code in C ++ 17 nicht portabel?

#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;

int main(int argc, char* argv[])
{
    std::cout << "Path is " << fs::path(argv[0]).parent_path() << '\n';
}

Scheint zumindest unter Linux für mich zu funktionieren.

Basierend auf der vorherigen Idee habe ich jetzt:

std::filesystem::path prepend_exe_path(const std::string& filename, const std::string& exe_path = "");

Mit Implementierung:

fs::path prepend_exe_path(const std::string& filename, const std::string& exe_path)
{
    static auto exe_parent_path = fs::path(exe_path).parent_path();
    return exe_parent_path / filename;
}

Und Initialisierungstrick in main():

(void) prepend_exe_path("", argv[0]);

Danke @Sam Redway für die argv [0] Idee. Und natürlich verstehe ich, dass es C ++ 17 viele Jahre nicht gab, als das OP die Frage stellte.

Nilo
quelle
0

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

Sie können feststellen, dass das Ergebnis nicht immer hübsch ist - Sie erhalten möglicherweise Dinge wie /foo/bar/../../baz/a.outoder /foo/bar//baz/a.out, aber ich glaube, dass es immer zu einem gültigen Pfad führt, der die ausführbare Datei benennt (beachten Sie, dass aufeinanderfolgende Schrägstriche in einem Pfad zu einem reduziert werden).

Ich habe zuvor eine Lösung mit envp(das dritte Argument, main()das unter Linux funktioniert hat, aber unter Windows nicht funktioniert hat) geschrieben. Daher empfehle ich im Wesentlichen dieselbe Lösung wie zuvor, aber mit der zusätzlichen Erklärung, warum sie tatsächlich korrekt ist auch wenn die Ergebnisse nicht schön sind.

John Zwinck
quelle
0

Wie Minok erwähnte, gibt es keine solche Funktionalität, die im C-Standard oder C ++ - Standard angegeben ist. Dies wird als rein betriebssystemspezifische Funktion angesehen und ist beispielsweise im POSIX-Standard festgelegt.

Thorsten79 hat gute Vorschläge gemacht, es ist Boost.Filesystem Bibliothek. Dies kann jedoch unpraktisch sein, wenn Sie für Ihr Programm keine Abhängigkeiten zur Verbindungszeit in binärer Form haben möchten.

Eine gute Alternative, die ich empfehlen würde, ist die Sammlung von STLSoft C ++ - Bibliotheken mit 100% Headern. Matthew Wilson (Autor von Büchern, die man unbedingt über C ++ lesen muss). Es gibt eine tragbare Fassade PlatformSTL bietet Zugriff auf die systemspezifische API: WinSTL für Windows und UnixSTL unter Unix, ist also eine tragbare Lösung. Alle systemspezifischen Elemente werden mithilfe von Merkmalen und Richtlinien angegeben, sodass es sich um ein erweiterbares Framework handelt. Natürlich gibt es eine Dateisystembibliothek.

Mloskot
quelle
0

Der Linux-Bash-Befehl, dessen Progname einen Pfad zum Programm meldet.

Selbst wenn man den Befehl which in Ihrem Programm ausgeben und die Ausgabe in eine tmp-Datei leiten könnte und das Programm anschließend diese tmp-Datei liest, wird es Ihnen nicht sagen, ob dieses Programm dasjenige ist, das ausgeführt wird. Hier erfahren Sie nur, wo sich ein Programm mit diesem Namen befindet.

Erforderlich ist es, Ihre Prozess-ID-Nummer zu erhalten und den Pfad zum Namen zu analysieren

In meinem Programm möchte ich wissen, ob das Programm aus dem bin-Verzeichnis 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 es unter Linux die eine Lösung gibt, die portabel ist.

Leslie Satenstein
quelle
0

Verwenden Sie realpath()in stdlib.hwie folgt:

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

Funktioniert mit C ++ 11 unter Verwendung des experimentellen Dateisystems und C ++ 14-C ++ 17 unter Verwendung des offiziellen Dateisystems.

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
}
TarmoPikaro
quelle
Gute Antwort, aber es ist undefiniertes Verhalten, dem Namespace Deklarationen oder Definitionen hinzuzufügenstd . Um dies zu vermeiden, können Sie sowohl die Namespaces std::filesystemals std::experimental::filesystemauch einen dritten Namespace Ihrer Wahl using std::filesystem::pathhinzufügen oder einfach verwenden , wenn Sie nichts dagegen haben, die Deklaration von pathzum globalen Namespace hinzuzufügen .
Cássio Renan
Ich denke, nachdem C ++ 14 experimentell :: Dateisystem nicht mehr verwendet wird, können Sie dies einfach vergessen? (geht in den ersten # if-Zweig)
TarmoPikaro