¿Cómo encuentro la ubicación del ejecutable en C? [duplicar]


Esta pregunta ya tiene una respuesta aquí:

¿Hay alguna forma en C/C++ de encontrar la ubicación (ruta completa) del programa ejecutado actualmente?

(El problema con argv[0] es que no da la ruta completa.)

Author: Peter Mortensen, 2009-06-01

9 answers

Para resumir:

  • En Unixes con /proc la manera realmente recta y realiable es:

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

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

    • readlink("/proc/self/path/a.out", buf, bufsize) (Solaris)

  • En Unixes sin /proc (es decir, si lo anterior falla):

    • Si argv [0] comienza con "/" (ruta absoluta) esta es la ruta.

    • De lo contrario, si argv[0] contiene " / " (ruta relativa) añádalo a cwd (asumir no ha sido cambiado todavía).

    • De lo contrario, busque en los directorios $PATH el ejecutable argv[0].

    Después puede ser razonable comprobar si el ejecutable no es realmente un enlace simbólico. Si es resolverlo en relación con el directorio de enlace simbólico.

    Este paso no es necesario en el método /proc (al menos para Linux). Allí el enlace simbólico proc apunta directamente al ejecutable.

    Tenga en cuenta que depende del proceso de llamada establecer argv[0] correctamente. Es la mayoría de las veces, sin embargo, hay ocasiones en las que no se puede confiar en el proceso de llamada (ej. setuid ejecutable).

  • En Windows: uso GetModuleFileName(NULL, buf, bufsize)

 182
Author: lispmachine,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-05-24 18:56:30

Use GetModuleFileName() función si está utilizando Windows.

 18
Author: Shino C G,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-01 07:43:33

Tenga en cuenta que los siguientes comentarios son solo para unix.

La respuesta pedante a esta pregunta es que no hay forma general de responder esta pregunta correctamente en todos los casos. Como has descubierto, argv [0] puede ser establecido en cualquier cosa por el proceso padre, y por lo tanto no necesita tener relación alguna con el nombre real del programa o su ubicación en el sistema de archivos.

Sin embargo, la siguiente heurística a menudo funciona:

  1. Si argv [0] es un valor absoluto path, asume que esta es la ruta completa al ejecutable.
  2. Si argv[0] es una ruta relativa, es decir, contiene un /, determine el directorio de trabajo actual con getcwd() y luego agregue argv[0] a él.
  3. Si argv[0] es una palabra simple, busque arg PATH buscando argv[0], y agregue argv[0] a cualquier directorio en el que lo encuentre.

Tenga en cuenta que todos estos pueden ser eludidos por el proceso que invocó el programa en cuestión. Finalmente, puede usar linux específico técnicas, como las mencionadas por emg-2. Probablemente existen técnicas equivalentes en otros sistemas operativos.

Incluso suponiendo que los pasos anteriores le den un nombre de ruta válido, es posible que aún no tenga el nombre de ruta que realmente desea (ya que sospecho que lo que realmente desea es encontrar un archivo de configuración en algún lugar). La presencia de enlaces duros significa que puede tener la siguiente situación:

-- 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

Ahora, el enfoque anterior (incluyendo, sospecho, / proc / p pid / exe) dar /some/where/else/foo como la ruta real al programa. Y, de hecho, es un camino real al programa, pero no el que querías. Tenga en cuenta que este problema no ocurre con enlaces simbólicos que son mucho más comunes en la práctica que los enlaces duros.

A pesar del hecho de que este enfoque es en principio poco fiable, funciona lo suficientemente bien en la práctica para la mayoría de los propósitos.

 15
Author: Dale Hagglund,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-01 08:45:04

No es una respuesta en realidad, sino solo una nota para tener en cuenta.

Como pudimos ver, el problema de encontrar la ubicación del ejecutable en ejecución es bastante complicado y específico de la plataforma en Linux y Unix. Uno debe pensar dos veces antes de hacer eso.

Si necesita su ubicación ejecutable para descubrir algunos archivos de configuración o recursos, tal vez debería seguir la forma Unix de colocar archivos en el sistema: ponga configs en /etc o /usr/local/etc o en el directorio principal del usuario actual, y /usr/share es un buen lugar para poner sus archivos fuente.

 9
Author: Michael,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-02 11:34:22

En muchos sistemas POSIX se puede comprobar un enlace sim ubicado en /proc/PID/exe. Algunos ejemplos:

# 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
Author: MestreLion,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-15 08:19:16

Recuerde que en sistemas Unix el binario puede haber sido eliminado desde que se inició. Es perfectamente legal y seguro en Unix. La última vez que revisé Windows no le permitirá eliminar un binario en ejecución.

/proc/self/exe seguirá siendo legible, pero no será realmente un enlace simbólico que funcione. Lo será... extraño.

 4
Author: Thomas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-16 09:05:50

Para Linux puedes encontrar la /proc/self/exe forma de hacer las cosas agrupada en una bonita biblioteca llamada binreloc, puedes encontrar la biblioteca en:

 3
Author: Grumbel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-08-05 21:40:54

En Mac OS X, utilice _NSGetExecutablePath.

Ver man 3 dyld y esta respuesta a una pregunta similar.

 3
Author: Tim Ruddick,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:47:23

Lo haría

1) Usa la función basename (): http://linux.die.net/man/3/basename
2) chdir () a ese directorio
3) Use getpwd () para obtener el directorio actual

De esa manera obtendrá el directorio en una forma ordenada y completa, en lugar de ./ o ../recipiente/.

Tal vez desee guardar y restaurar el directorio actual, si eso es importante para su programa.

 0
Author: JCCyC,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-19 19:03:20