Eigentlich keine Antwort, sondern nur eine Notiz, die Sie im Hinterkopf behalten sollten.
Wie wir sehen konnten, ist das Problem, den Speicherort der laufenden ausführbaren Datei zu finden, ziemlich knifflig und plattformspezifisch in Linux und Unix. Man sollte es sich vorher gut überlegen.
Wenn Sie Ihren ausführbaren Speicherort benötigen, um einige Konfigurations- oder Ressourcendateien zu finden, sollten Sie vielleicht der Unix-Methode folgen, um Dateien im System zu platzieren:Put configs to /etc
oder /usr/local/etc
oder im Home-Verzeichnis des aktuellen Benutzers und /usr/share
ist ein guter Ort, um Ihre Ressourcendateien abzulegen.
Verwenden Sie die Funktion GetModuleFileName(), wenn Sie Windows verwenden.
Bitte beachten Sie, dass die folgenden Kommentare nur für Unix gelten.
Die pedantische Antwort auf diese Frage ist, dass es kein Allgemeines gibt Möglichkeit, diese Frage in allen Fällen richtig zu beantworten. Wie Sie festgestellt haben, kann argv[0] vom übergeordneten Prozess auf einen beliebigen Wert gesetzt werden und muss daher keinerlei Beziehung zum tatsächlichen Namen des Programms oder seiner Position im Dateisystem haben.
Die folgende Heuristik funktioniert jedoch häufig:
- Wenn argv[0] ein absoluter Pfad ist, nehmen Sie an, dass dies der vollständige Pfad zur ausführbaren Datei ist.
- Falls argv[0] ein relativer Pfad ist, dh eine
/
enthält , ermitteln Sie das aktuelle Arbeitsverzeichnis mit getcwd() und hängen Sie dann argv[0] daran an. - Wenn argv[0] ein einfaches Wort ist, suchen Sie $PATH nach argv[0] und hängen Sie argv[0] an das Verzeichnis an, in dem Sie es finden.
Beachten Sie, dass all dies durch den Prozess umgangen werden kann, der das betreffende Programm aufgerufen hat. Schließlich können Sie linuxspezifische Techniken verwenden, wie sie von emg-2 erwähnt werden. Es gibt wahrscheinlich äquivalente Techniken auf anderen Betriebssystemen.
Selbst wenn Sie davon ausgehen, dass die obigen Schritte Ihnen einen gültigen Pfadnamen geben, haben Sie möglicherweise immer noch nicht den eigentlich gewünschten Pfadnamen (da ich vermute, dass Sie eigentlich irgendwo eine Konfigurationsdatei finden möchten). Das Vorhandensein von festen Links bedeutet, dass Sie die folgende Situation haben können:
-- assume /app/bin/foo is the actual program
$ mkdir /some/where/else
$ ln /app/bin/foo /some/where/else/foo # create a hard link to foo
$ /some/where/else/foo
Nun, der obige Ansatz (einschließlich, wie ich vermute, /proc/$pid/exe) ergibt /some/where/else/foo
als der eigentliche Pfad zum Programm. Und tatsächlich ist es ein echten Pfad zum Programm, nur nicht den, den Sie wollten. Beachten Sie, dass dieses Problem bei symbolischen Links nicht auftritt, die in der Praxis viel häufiger vorkommen als harte Links.
Obwohl dieser Ansatz im Prinzip unzuverlässig ist, funktioniert er in der Praxis für die meisten Zwecke gut genug.
Zusammenfassend:
-
Auf Unixen mit
/proc
Ein wirklich direkter und zuverlässiger Weg ist:-
readlink("/proc/self/exe", buf, bufsize)
(Linux) -
readlink("/proc/curproc/file", buf, bufsize)
(FreeBSD) -
readlink("/proc/self/path/a.out", buf, bufsize)
(Solaris)
-
-
Auf Unixen ohne
/proc
(d.h. wenn obiges fehlschlägt):-
Wenn argv[0] mit "/" (absoluter Pfad) beginnt, ist dies der Pfad.
-
Andernfalls, wenn argv[0] "/" (relativer Pfad) enthält, hänge es an cwd an (vorausgesetzt, es wurde noch nicht geändert).
-
Suchen Sie andernfalls Verzeichnisse in
$PATH
für die ausführbare Dateiargv[0]
.
Danach kann es sinnvoll sein zu überprüfen, ob die ausführbare Datei nicht wirklich ein Symlink ist. Wenn es relativ zum Symlink-Verzeichnis aufgelöst wird.
Dieser Schritt ist in der /proc-Methode (zumindest für Linux) nicht erforderlich. Dort zeigt der proc-Symlink direkt auf die ausführbare Datei.
Beachten Sie, dass es Sache des aufrufenden Prozesses ist,
argv[0]
zu setzen richtig. Es ist meistens richtig, aber es gibt Fälle, in denen dem aufrufenden Prozess nicht vertraut werden kann (z. B. ausführbare setuid). -
-
Unter Windows:Verwenden Sie
GetModuleFileName(NULL, buf, bufsize)