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

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

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

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

9 ответов


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

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

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

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

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

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

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

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

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

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

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

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

  • в 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 (), чтобы получить текущий каталог

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

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