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

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

(argv[0]的问题在于它没有给出完整的路径。)

97121 次浏览

在许多 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

如果使用 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作为程序的真正路径。实际上,它是 到程序的真正路径,只是不是你想要的那条。请注意,这个问题不会发生在符号链接上,符号链接在实践中比硬链接更常见。

尽管这种方法在原则上是不可靠的,但是在实践中对于大多数目的来说都足够有效。

总结一下:

  • 对于使用 /proc的 Unixes 来说,真正直接可行的方法是:

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

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

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

  • 对于没有 /proc的 Unixes (即,如果上述操作失败) :

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

    • 否则,如果 argv [0]包含“/”(相对路径) ,则将其附加到 cwd (假设它还没有被改变)

    • 否则在 $PATH中的目录中搜索可执行 argv[0]

    然后,可以合理地检查可执行文件是否实际上不是符号链接。 如果是相对于 symlink 目录解析它,则为。

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

    请注意,正确设置 argv[0]取决于调用进程。 在大多数情况下,这是正确的,但也有不能信任调用进程的情况(例如。Setuid 可执行文件)。

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

请记住,在 Unix 系统上,二进制文件可能从一开始就被删除了。在 Unix 上是完全合法和安全的。上次我选择的 Windows 将不允许您删除运行的二进制文件。

/proc/self/exe 仍然是可读的,但它实际上不会是一个工作的符号链接。

实际上不是答案,只是一个需要记住的提示。

正如我们所看到的,在 Linux 和 Unix 中,找到运行可执行文件的位置是一个非常棘手的问题,并且是特定于平台的。一个人在做那件事之前应该三思而后行。

如果您需要您的可执行位置来发现一些配置或资源文件,也许您应该遵循 Unix 的方式放置文件在系统中: 把配置到 /etc/usr/local/etc或在当前的用户主目录,和 /usr/share是一个很好的地方放置您的资源文件。

我会的

1)使用 basename ()函数: http://linux.die.net/man/3/basename
2) chdir ()到该目录
3)使用 getpwd ()获取工作目录

这样,您将获得一个整洁、完整的目录,而不是./或. ./bin/。

也许你想保存和恢复工作目录,如果这对你的程序很重要的话。

对于 Linux 来说,你可以找到 /proc/self/exe的方法来处理捆绑在一个叫做 binreloc 的库中的事情,你可以在以下网址找到这个库:

在 Mac OS X 上,使用 _NSGetExecutablePath

对于类似的问题,请参阅 man 3 dyld这个答案