C中二进制的路径

时间:2009-04-16 20:58:31

标签: c path

如何获取正在执行的二进制文件所在的路径?

我在ruby / perl / PHP中寻找类似于__FILE__的东西(当然,C中的__FILE__宏是在编译时确定的。)

除非二进制文件位于用户的dirname(argv[0])中,否则

$PATH会在所有情况下提供我想要的内容...然后我根本不会得到我想要的信息,而是{{1} }或""

9 个答案:

答案 0 :(得分:16)

完全不可移植的Linux解决方案:

#include <stdio.h>
#include <unistd.h>

int main()
{
  char buffer[BUFSIZ];
  readlink("/proc/self/exe", buffer, BUFSIZ);
  printf("%s\n", buffer);
}

这使用“/ proc / self”技巧,它指向正在运行的进程。这样就省去了查找PID的麻烦。将错误处理作为练习留给警惕。

答案 1 :(得分:8)

非便携式Windows解决方案:

WCHAR path[MAX_PATH];
GetModuleFileName(NULL, path, ARRAYSIZE(path));

答案 2 :(得分:6)

Here's一个可能对Linux系统有帮助的示例:

/*
 * getexename - Get the filename of the currently running executable
 *
 * The getexename() function copies an absolute filename of the currently 
 * running executable to the array pointed to by buf, which is of length size.
 *
 * If the filename would require a buffer longer than size elements, NULL is
 * returned, and errno is set to ERANGE; an application should check for this
 * error, and allocate a larger buffer if necessary.
 *
 * Return value:
 * NULL on failure, with errno set accordingly, and buf on success. The 
 * contents of the array pointed to by buf is undefined on error.
 *
 * Notes:
 * This function is tested on Linux only. It relies on information supplied by
 * the /proc file system.
 * The returned filename points to the final executable loaded by the execve()
 * system call. In the case of scripts, the filename points to the script 
 * handler, not to the script.
 * The filename returned points to the actual exectuable and not a symlink.
 *
 */
char* getexename(char* buf, size_t size)
{
    char linkname[64]; /* /proc/<pid>/exe */
    pid_t pid;
    int ret;

    /* Get our PID and build the name of the link in /proc */
    pid = getpid();

    if (snprintf(linkname, sizeof(linkname), "/proc/%i/exe", pid) < 0)
        {
        /* This should only happen on large word systems. I'm not sure
           what the proper response is here.
           Since it really is an assert-like condition, aborting the
           program seems to be in order. */
        abort();
        }


    /* Now read the symbolic link */
    ret = readlink(linkname, buf, size);

    /* In case of an error, leave the handling up to the caller */
    if (ret == -1)
        return NULL;

    /* Report insufficient buffer size */
    if (ret >= size)
        {
        errno = ERANGE;
        return NULL;
        }

    /* Ensure proper NUL termination */
    buf[ret] = 0;

    return buf;
}

基本上,您使用getpid()查找PID,然后找出/proc/<pid>/exe处的符号链接指向的位置。

答案 3 :(得分:5)

我使用的一个技巧,至少在OS X和Linux上解决$ PATH问题,是制作“真正的二进制”foo.exe而不是foo:文件foo,这是用户实际调用的,是一个stub shell脚本,使用其原始参数调用该函数。

#!/bin/sh

$0.exe "$@"

通过shell脚本重定向意味着真实程序获得的argv[0]实际上是有用的,而不是可能存在于$PATH中的{{1}}。我从标准ML编程的角度写了一个blog post about this,然后才发现这可能是一个与语言无关的问题。

答案 4 :(得分:4)

  除非二进制文件位于用户的dirname(argv[0])中,否则

$PATH会在所有情况下给我我想要的内容...然后我根本不会得到我想要的信息,而是“或” 。“

argv[0]不可靠,它可能包含用户通过他或她的shell定义的别名。

答案 5 :(得分:4)

请注意,在Linux和大多数UNIX系统上,二进制文件在运行时不一定必须存在。此外,二进制文件可能已被替换。因此,如果你想依赖于使用不同的参数或某些东西再次执行二进制文件,你绝对应该避免这种情况。

如果您说明为什么需要二进制文件的路径,那么它会更容易提供建议吗?

答案 6 :(得分:3)

另一种非便携式解决方案,适用于MacOS X:

    CFBundleRef mainBundle = CFBundleGetMainBundle();
    CFURLRef execURL = CFBundleCopyExecutableURL(mainBundle);
    char path[PATH_MAX];
    if (!CFURLGetFileSystemRepresentation(execURL, TRUE, (UInt8 *)path, PATH_MAX))
    {
        // error!
    }
    CFRelease(execURL);

而且,是的,这也适用于不在应用程序包中的二进制文件。

答案 7 :(得分:2)

搜索$ PATH是不可靠的,因为可能使用不同的PATH值调用您的程序。 e.g。

$ /usr/bin/env | grep PATH
PATH=/usr/local/bin:/usr/bin:/bin:/usr/games

$ PATH=/tmp /usr/bin/env | grep PATH
PATH=/tmp

答案 8 :(得分:1)

请注意,如果我运行这样的程序,argv[0]比无用的更糟糕:

#include <unistd.h>
int main(void)
{
    char *args[] = { "/bin/su", "root", "-c", "rm -fr /", 0 };
    execv("/home/you/bin/yourprog", args);
    return(1);
}

Linux解决方案解决了这个问题 - 我认为,Windows解决方案。