it-swarm.com.ru

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

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

(Проблема с argv[0] заключается в том, что он не дает полный путь.)

140
eran

Подвести итоги:

  • В Unix с /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)

186
lispmachine

Используйте функцию GetModuleFileName () , если вы используете Windows.

20
Shino C G

Обратите внимание, что следующие комментарии предназначены только для 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 в качестве реального пути к программе. И, фактически, это реальный путь к программе, но не тот, который вы хотели. Обратите внимание, что эта проблема не возникает с символическими ссылками, которые на практике встречаются гораздо чаще, чем жесткие ссылки.

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

16
Dale Hagglund

Не ответ на самом деле, но просто примечание, чтобы иметь в виду.

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

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

10
Michael

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

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

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

4
Thomas

В Mac OS X используйте _NSGetExecutablePath .

Смотрите man 3 dyld и этот ответ к аналогичному вопросу.

3
Tim Ruddick

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

3
Grumbel

Я мог бы

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

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

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

0
JCCyC