如何在C中找到可执行文件的位置?

在C / C ++中有没有办法找到当前执行的程序的位置(完整路径)?

argv[0]的问题是它不能提供完整的路径。)

总结:

  • 在使用/proc Unix上,真正直接和可行的方法是:

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

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

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

  • 在没有/proc Unix上(即如果以上失败):

    • 如果argv [0]以“/”(绝对路径)开头,则为路径。

    • 否则,如果argv [0]包含“/”(相对路径),则将其追加到cwd(假设它尚未更改)。

    • 否则,在$PATH搜索可执行文件argv[0]

    之后,检查可执行文件是否实际上不是符号链接可能是合理的。 如果它解决了它相对于symlink目录。

    这个步骤在/ proc方法中是不必要的(至少对于Linux来说)。 那里的符号链接直接指向可执行文件。

    请注意,由调用进程正确设置argv[0] 。 这是正确的大多数时候,但有时,调用过程不能被信任(例如setuid可执行文件)。

  • 在Windows上:使用GetModuleFileName(NULL, buf, bufsize)

如果您使用的是Windows,请使用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作为程序的真正路径。 事实上,这是一个真正的方案,而不是你想要的。 请注意,这个问题不会出现在实践中比硬链接更常见的符号链接。

尽管这种方法原则上是不可靠的,但在大多数情况下,它在实践中运作良好。

实际上并不是一个答案,只是一个要记住的记录。

正如我们所看到的,在Linux和Unix中查找正在运行的可执行文件的位置是非常棘手和特定于平台的。 在做这件事之前,应该三思。

如果你需要你的可执行文件位置来发现一些配置文件或者资源文件,也许你应该按照Unix的方式把文件放在系统中:把配置文件放在/etc或者/usr/local/etc或者当前用户的home目录下, /usr/share是放置资源文件的好地方。

在许多POSIX系统中,您可以检查位于/ proc / PID / exe下的simlink。 几个例子:

 # 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 

对于Linux,你可以找到/proc/self/exe bin / bin / bin / bin / bin /proc/self/exe方式,在bin里可以找到这个库。

在Mac OS X上,使用_NSGetExecutablePath

man 3 dyld和这个答案类似的问题。

请记住,在Unix系统中,二进制文件可能在启动后被删除。 在Unix上它是完全合法和安全的。 最后我检查Windows不会允许您删除正在运行的二进制文件。

/ proc / self / exe仍然是可读的,但它不会真正成为工作符号链接。 这将是…奇怪。

我会

1)使用basename()函数: http : //linux.die.net/man/3/basename
2)chdir()到那个目录
3)使用getpwd()获取当前目录

这样,你会得到一个整洁,完整的形式,而不是./或../bin/的目录。

也许你会想保存和恢复当前目录,如果这对你的程序很重要。