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

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

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

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

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

Как мы могли видеть, проблема определения местоположения исполняемого файла довольно сложна и зависит от платформы в 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/.

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

Другие вопросы по тегам