如何获取程序正在运行的目录?

时间:2020-03-06 14:49:13  来源:igfitidea点击:

是否有平台无关和文件系统无关的方法来获取使用C / C ++从中运行程序的目录的完整路径?不要与当前工作目录混淆。 (除非是标准库,例如clib或者STL,否则请不要建议它们。)

(如果没有与平台/文件系统无关的方法,那么也欢迎在Windows和Linux中适用于特定文件系统的建议。)

解决方案

对于Win32,GetCurrentDirectory应该可以解决问题。

不,没有标准方法。我相信C / C ++标准甚至不考虑目录(或者其他文件系统组织)的存在。

在Windows上,当hModule参数设置为NULL时,GetModuleFileName()将返回当前进程的可执行文件的完整路径。我帮不上Linux。

另外,我们还应该澄清是要使用当前目录还是要使用程序映像/可执行文件所在的目录。就目前情况而言,问题在这一点上有点模棱两可。

如果要使用没有库的标准方式:否。目录的整个概念未包含在标准中。

如果我们同意对标准库的某种(便携式)依赖关系是可以的:使用Boost的文件系统库,并请求initial_path()。

恕我直言,我们可以通过良好的业力获得最大的收益(Boost是一套完善的高质量库)

在POSIX平台上,可以使用getcwd()。

在Windows上,我们可能会使用_getcwd(),因为已不建议使用getcwd()。

对于标准库,如果Boost对我们而言已经足够标准了,我会建议使用Boost :: filesystem,但是它们似乎已从提案中删除了路径标准化。我们可能要等到TR2可以立即用于完整的标准解决方案。

也许用argv [0]连接当前工作目录?我不确定这是否适用于Windows,但适用于Linux。

例如:

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

int main(int argc, char **argv) {
    char the_path[256];

    getcwd(the_path, 255);
    strcat(the_path, "/");
    strcat(the_path, argv[0]);

    printf("%s\n", the_path);

    return 0;
}

运行时,它输出:

jeremy@jeremy-desktop:~/Desktop$ ./test

  /home/jeremy/Desktop/./test

我们不能为此目的使用argv [0],通常它确实包含可执行文件的完整路径,但不一定可以在字段中使用任意值创建进程。

另外请注意,当前目录和带有可执行文件的目录是两件不同的事情,因此getcwd()也不会对我们有所帮助。

在Windows上,使用GetModuleFileName(),在Linux上,读取/ dev / proc / procID / ..文件。

Boost Filesystem的" initial_path()"的行为类似于POSIX的" getcwd()",我们自己也不需要做任何事情,但是将argv [0]添加到其中任何一个上都可以。

我们可能会注意到结果并不总是很漂亮-我们可能会得到诸如/ foo / bar /../../ baz / a.out或者/ foo / bar // baz / a.out之类的东西,但我相信它总是会产生一个有效的路径来命名可执行文件(请注意,路径中的连续斜杠会折叠成一个)。

之前,我曾使用envp(main()的第三个参数)编写了一个解决方案,该解决方案在Linux上有效,但在Windows上似乎不可行,因此我实质上建议与其他人使用相同的解决方案,但建议使用即使结果不佳,也要解释为什么它实际上是正确的。

如果我们在程序首次启动时获取当前目录,那么我们实际上就拥有了程序从其启动的目录。将值存储在变量中,然后在程序中引用它。这不同于保存当前可执行程序文件的目录。它不一定是同一目录。如果有人从命令提示符处运行该程序,则即使该程序文件位于其他位置,也正在从命令提示符的当前工作目录中运行该程序。

getcwd是POSIX函数,并且所有POSIX兼容平台均支持开箱即用。我们不必做任何特殊的事情(除了在Unix上抬头unistd.h和在Windows上抬头direct.h之外)。

由于我们正在创建C程序,它将与默认的c运行时库链接,该库由系统中的所有进程链接到该库(避免了特制的异常),并且默认情况下将包含此函数。 CRT从不被视为外部库,因为它为OS提供了基本的标准兼容接口。

在Windows上,不建议使用getcwd函数,而推荐使用_getcwd。我认为我们可以以这种方式使用它。

#include <stdio.h>  /* defines FILENAME_MAX */
#ifdef WINDOWS
    #include <direct.h>
    #define GetCurrentDir _getcwd
#else
    #include <unistd.h>
    #define GetCurrentDir getcwd
 #endif

 char cCurrentPath[FILENAME_MAX];

 if (!GetCurrentDir(cCurrentPath, sizeof(cCurrentPath)))
     {
     return errno;
     }

cCurrentPath[sizeof(cCurrentPath) - 1] = '
int bytes = GetModuleFileName(NULL, pBuf, len);
if(bytes == 0)
    return -1;
else
    return bytes;
'; /* not really required */ printf ("The current working directory is %s", cCurrentPath);

这是获取执行应用程序完整路径的代码:

视窗:

char szTmp[32];
sprintf(szTmp, "/proc/%d/exe", getpid());
int bytes = MIN(readlink(szTmp, pBuf, len), len - 1);
if(bytes >= 0)
    pBuf[bytes] = '##代码##';
return bytes;

Linux:

##代码##

只是迟来地堆在这里,...

没有标准的解决方案,因为这些语言与底层文件系统无关,因此,正如其他人所说的那样,基于目录的文件系统的概念不在c / c ++语言的范围之内。

最重要的是,我们不想要当前的工作目录,而是想要程序正在运行的目录,它必须考虑程序如何到达其所在位置,即,它是通过fork生成为新进程等的。如解决方案所示,获取程序正在运行的目录,要求我们从相关操作系统的过程控制结构中获取该信息,这是对此问题的唯一授权。因此,根据定义,它是特定于OS的解决方案。

正如Minok所提到的,在ini C标准或者C ++标准中没有指定这样的功能。这被认为是纯粹的特定于OS的功能,例如,它是在POSIX标准中指定的。

Thorsten79给出了很好的建议,它是Boost.Filesystem库。但是,如果我们不希望程序具有二进制形式的任何链接时相关性,这可能会带来不便。

我推荐的一个很好的选择是收集100%仅标头的STLSoft C ++库Matthew Wilson(有关C ++的必读书籍的作者)。 PlatformSTL具有可移植的外观,可访问系统特定的API:Windows的WinSTL和Unix上的UnixSTL,因此是可移植的解决方案。所有特定于系统的元素都是使用特征和策略来指定的,因此它是可扩展的框架。当然,提供了文件系统库。