在C / C ++中是否有办法找到当前执行程序的位置(完整路径)?
(argv[0]
的问题在于它没有提供完整路径。)
答案 0 :(得分:185)
总结:
在具有/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]
的目录。
之后,检查可执行文件是否实际上不是符号链接可能是合理的。 如果它是相对于符号链接目录解析它。
/ proc方法中不需要此步骤(至少对于Linux)。 proc符号链接直接指向可执行文件。
请注意,由调用进程正确设置argv[0]
。
大多数时候都是正确的,但是有时候调用进程不可信(例如setuid可执行文件)。
在Windows上:使用GetModuleFileName(NULL, buf, bufsize)
答案 1 :(得分:20)
如果您使用的是Windows,请使用GetModuleFileName()功能。
答案 2 :(得分:16)
请注意,以下注释仅限unix。
对这个问题的迂腐回答是,在所有情况下,没有一般方法正确回答这个问题。正如您所发现的那样,父进程可以将argv [0]设置为任何内容,因此无需与程序的实际名称或其在文件系统中的位置有任何关系。
但是,以下启发式通常有效:
/
,请使用getcwd()确定当前工作目录,然后将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
作为程序的真实路径。而且,事实上,它是 程序的真实路径,而不是您想要的路径。请注意,符号链接不会出现此问题,这在实践中比硬链接更常见。
尽管这种方法原则上不可靠,但在大多数情况下,它在实践中运作良好。
答案 3 :(得分:10)
实际上不是答案,只是要记住的一个注意事项。
正如我们所看到的,在Linux和Unix中找到运行可执行文件的位置的问题非常棘手并且特定于平台。在做这件事之前,应该三思而后行。
如果您需要可执行位置来发现某些配置或资源文件,可能应该按照Unix方式在系统中放置文件:将配置文件放到/etc
或/usr/local/etc
或当前用户主页目录,/usr/share
是放置资源文件的好地方。
答案 4 :(得分:6)
在许多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
答案 5 :(得分:4)
请记住,在Unix系统上,二进制文件自启动以来可能已被删除。它在Unix上完全合法且安全。最后我检查了Windows将不允许您删除正在运行的二进制文件。
/ proc / self / exe仍然可读,但它实际上不是一个有效的符号链接。这将是......奇怪的。
答案 6 :(得分:3)
对于Linux,您可以在名为binreloc的漂亮库中找到捆绑的/proc/self/exe
方式,您可以在以下位置找到该库:
答案 7 :(得分:3)
在Mac OS X上,使用_NSGetExecutablePath
。
请参阅man 3 dyld
和this answer类似的问题。
答案 8 :(得分:0)
我会
1)使用basename()函数:http://linux.die.net/man/3/basename
2)chdir()到该目录
3)使用getpwd()获取当前目录
这样你就可以得到一个整洁的完整形式的目录,而不是./或../ bin /.
如果这对您的程序很重要,也许您会想要保存并恢复当前目录。