Как найти расположение исполняемого файла в C? [дубликат]


этот вопрос уже есть ответ здесь:

  • Поиск пути текущего исполняемого файла без /proc / self / exe 12 ответов

есть ли способ в C/C++ найти местоположение (полный путь) текущей выполняемой программы?

(проблема с argv[0] Это то, что он не дает полный путь.)

9 135

9 ответов:

подведем итоги:

  • на Униксах с /proc действительно прямой и реальный способ - это:

    • readlink("/proc/self/exe", buf, bufsize) (Linux)

    • readlink("/proc/curproc/file", buf, bufsize) (FreeBSD)

    • readlink("/proc/self/path/a.out", buf, bufsize) (Солярис)

  • на Unixes без /proc (т. е. если выше не получится):

    • если argv[0] начинается с "/" (полный путь) это путь.

    • в противном случае, если argv[0] содержит "/" (относительный путь), добавьте его в cwd (предполагая, что он еще не был изменен).

    • в противном случае поиск в каталогах $PATH для исполняемого файла argv[0].

    после этого может быть разумно проверить, не является ли исполняемый файл на самом деле символической ссылкой. Если это разрешить его относительно каталога символической ссылки.

    этот шаг не требуется в методе /proc (at крайней мере для Linux). Там символическая ссылка proc указывает непосредственно на исполняемый файл.

    обратите внимание, что это до вызывающего процесса, чтобы установить argv[0] правильно. Это верно в большинстве случаев, однако есть случаи, когда вызывающий процесс не может быть доверенным (ex. дополнительное исполняемый).

  • в Windows: используйте GetModuleFileName(NULL, buf, bufsize)

использовать GetModuleFileName()

обратите внимание, что следующие комментарии только для unix.

педантичный ответ на этот вопрос заключается в том, что нет общие способ ответить на этот вопрос правильно во всех случаях. Как вы обнаружили, argv[0] может быть установлен на что угодно родительским процессом, и поэтому не должен иметь никакого отношения к фактическому имени программы или ее местоположению в файловой системе.

однако часто работает следующая эвристика:

  1. если argv[0] является абсолютным путем, предположим, что это полный путь к исполняемому файлу.
  2. если argv[0] является относительным путем, т. е. содержит /, определите текущий рабочий каталог с помощью getcwd (), а затем добавьте к нему argv[0].
  3. если 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 как реальный путь к программе. И, по сути, это a реальный путь к программе, только не тот, который вы хотели. Обратите внимание, что эта проблема не возникает с символическими ссылками, которые гораздо чаще встречаются на практике, чем жесткие ссылки.

несмотря на то, что этот подход в принципе ненадежен, он достаточно хорошо работает на практике для большинства цели.

не ответ на самом деле, но просто к сведению, имейте в виду.

как мы могли видеть, проблема поиска места запуска исполняемого файла довольно сложна и специфична для платформы в Linux и Unix. Нужно дважды подумать, прежде чем делать это.

Если вам нужно ваше исполняемое местоположение для обнаружения некоторых файлов конфигурации или ресурсов, возможно, вы должны следовать Unix способ размещения файлов в системе: put configs to /etc или /usr/local/etc или в текущем доме пользователя каталог, и /usr/share это хорошее место для размещения файлов ресурсов.

во многих системах 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

помните, что в системах Unix двоичный файл может быть удален с момента его запуска. Это совершенно законно и безопасно в Unix. Насколько я знаю Windows не позволит вам удалить запущенный бинарник.

/proc/self / exe по-прежнему будет читаться, но это не будет рабочая символическая ссылка на самом деле. Так и будет... странный.

для Linux вы можете найти /proc/self/exe способ делать вещи, связанные в хорошей библиотеке под названием binreloc, вы можете найти библиотеку по адресу:

на Mac OS X Используйте _NSGetExecutablePath.

посмотреть man 3 dyld и ответ на подобный вопрос.

Я

1) Используйте функцию basename ():http://linux.die.net/man/3/basename
2) chdir () в этот каталог
3) Используйте getpwd (), чтобы получить текущий каталог

таким образом, вы получите каталог в аккуратной, полной форме, а не ./ или. ./закром./

возможно, вы захотите сохранить и восстановить текущий каталог, если это важно для вашей программы.