Как мне найти расположение исполняемого файла в C?
Есть ли способ в C/C++ найти местоположение (полный путь) текущей исполняемой программы?
(Проблема с argv[0]
является то, что это не дает полный путь.)
9 ответов
Подвести итоги:
На Unixes с
/proc
действительно прямой и надежный способ заключается в:readlink("/proc/self/exe", buf, bufsize)
(Linux)readlink("/proc/curproc/file", buf, bufsize)
(FreeBSD)readlink("/proc/self/path/a.out", buf, bufsize)
(Solaris)
На Unixes без
/proc
(т. е. если выше не удается):Если argv[0] начинается с "/" (абсолютный путь), это путь.
В противном случае, если argv[0] содержит "/" (относительный путь), добавьте его в cwd (при условии, что он еще не был изменен).
В противном случае поиск каталогов в
$PATH
для исполняемого файлаargv[0]
,
После этого может быть разумным проверить, не является ли исполняемый файл символической ссылкой. Если это разрешить это относительно каталога символической ссылки.
Этот шаг не является обязательным в методе /proc (по крайней мере, для Linux). Там символическая ссылка proc указывает непосредственно на исполняемый файл.
Обратите внимание, что это зависит от вызывающего процесса, чтобы установить
argv[0]
правильно. Это верно в большинстве случаев, однако бывают случаи, когда вызывающему процессу нельзя доверять (например, исполняемый файл setuid).В Windows: используйте
GetModuleFileName(NULL, buf, bufsize)
Используйте функцию GetModuleFileName(), если вы используете Windows.
Обратите внимание, что следующие комментарии предназначены только для Unix.
Педантичный ответ на этот вопрос заключается в том, что нет общего способа правильно ответить на этот вопрос во всех случаях. Как вы обнаружили, argv[0] может быть установлен на что-либо вообще родительским процессом, и поэтому не должен иметь никакого отношения к реальному имени программы или ее расположению в файловой системе.
Однако часто работает следующая эвристика:
- Если argv [0] является абсолютным путем, предположим, что это полный путь к исполняемому файлу.
- Если argv [0] является относительным путем, то есть он содержит
/
Определите текущий рабочий каталог с помощью getcwd() и добавьте к нему argv [0]. - Если argv [0] - простое слово, ищите $PATH, ища argv[0], и добавьте argv [0] в любой каталог, в котором вы его найдете.
Обратите внимание, что все это может быть обойдено процессом, который вызвал данную программу. Наконец, вы можете использовать Linux-специфические методы, такие как упомянутые emg-2. Вероятно, есть эквивалентные методы в других операционных системах.
Даже если предположить, что приведенные выше шаги дают вам правильное имя пути, у вас все равно может не быть пути, который вы на самом деле хотите (так как я подозреваю, что на самом деле вы хотите где-то найти файл конфигурации). Наличие жестких ссылок означает, что вы можете иметь следующую ситуацию:
-- 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
Теперь приведенный выше подход (включая, я подозреваю, /proc/$pid/exe) даст /some/where/else/foo
как реальный путь к программе. И на самом деле, это реальный путь к программе, а не тот, который вы хотели. Обратите внимание, что эта проблема не возникает с символическими ссылками, которые на практике встречаются гораздо чаще, чем жесткие ссылки.
Несмотря на то, что этот подход в принципе ненадежен, на практике он работает достаточно хорошо для большинства целей.
На самом деле не ответ, а просто примечание, о котором следует помнить.
Как мы могли видеть, проблема определения местоположения исполняемого файла довольно сложна и зависит от платформы в Linux и Unix. Надо дважды подумать, прежде чем делать это.
Если вам нужно ваше исполняемое местоположение для обнаружения некоторых файлов конфигурации или ресурсов, возможно, вам следует придерживаться Unix-способа размещения файлов в системе: /etc
или же /usr/local/etc
или в домашнем каталоге текущего пользователя, и /usr/share
это хорошее место для размещения ваших файлов ресурсов.
Помните, что в системах Unix двоичный файл мог быть удален с момента его запуска. Это абсолютно законно и безопасно в Unix. Последнее, что я проверил, Windows не позволит вам удалить работающий бинарный файл.
/ proc / self / exe по-прежнему будет читабельным, но на самом деле это не будет рабочая символическая ссылка. Это будет... странно.
Во многих системах POSIX вы можете проверить simlink, расположенный в /proc/PID/exe. Несколько примеров:
# file /proc/*/exe
/proc/1001/exe: symbolic link to /usr/bin/distccd
/proc/1023/exe: symbolic link to /usr/sbin/sendmail.sendmail
/proc/1043/exe: symbolic link to /usr/sbin/crond
В Mac OS X используйте _NSGetExecutablePath
,
Увидеть man 3 dyld
и это ответ на аналогичный вопрос.
Для Linux вы можете найти /proc/self/exe
способ делать вещи в хорошей библиотеке binreloc, вы можете найти библиотеку по адресу:
Я мог бы
1) Используйте функцию basename(): http://linux.die.net/man/3/basename
2) chdir () в этот каталог
3) Используйте getpwd(), чтобы получить текущий каталог
Таким образом, вы получите каталог в аккуратной, полной форме вместо./ или../bin/.
Возможно, вы захотите сохранить и восстановить текущий каталог, если это важно для вашей программы.