280

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

(如果没有与平台/文件系统无关的方法,也欢迎在 Windows 和 Linux 中针对特定文件系统工作的建议。)

4

25 回答 25

192

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

视窗:

char pBuf[256];
size_t len = sizeof(pBuf); 
int bytes = GetModuleFileName(NULL, pBuf, len);
return bytes ? bytes : -1;

Linux:

int bytes = MIN(readlink("/proc/self/exe", pBuf, len), len - 1);
if(bytes >= 0)
    pBuf[bytes] = '\0';
return bytes;
于 2008-10-13T16:01:28.090 回答
172

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

getcwd 是一个 POSIX 函数,所有兼容 POSIX 的平台都支持开箱即用。您不必做任何特别的事情(除了在 Unix 上包含正确的头文件 unistd.h 和在 Windows 上包含 direct.h )。

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

在 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] = '\0'; /* not really required */

printf ("The current working directory is %s", cCurrentPath);
于 2008-09-28T06:04:04.923 回答
46

这是来自cplusplus 论坛

在窗户上:

#include <string>
#include <windows.h>

std::string getexepath()
{
  char result[ MAX_PATH ];
  return std::string( result, GetModuleFileName( NULL, result, MAX_PATH ) );
}

在 Linux 上:

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

std::string getexepath()
{
  char result[ PATH_MAX ];
  ssize_t count = readlink( "/proc/self/exe", result, PATH_MAX );
  return std::string( result, (count > 0) ? count : 0 );
}

在 HP-UX 上:

#include <string>
#include <limits.h>
#define _PSTAT64
#include <sys/pstat.h>
#include <sys/types.h>
#include <unistd.h>

std::string getexepath()
{
  char result[ PATH_MAX ];
  struct pst_status ps;

  if (pstat_getproc( &ps, sizeof( ps ), 0, getpid() ) < 0)
    return std::string();

  if (pstat_getpathname( result, PATH_MAX, &ps.pst_fid_text ) < 0)
    return std::string();

  return std::string( result );
}
于 2013-10-23T07:37:39.890 回答
29

如果您想要一种没有库的标准方式:不。目录的整个概念不包含在标准中。

如果您同意对接近标准库的某些(可移植)依赖是可以的:使用Boost 的文件系统库并请求initial_path()

恕我直言,你可以得到尽可能接近,具有良好的业力(Boost 是一套完善的高质量库)

于 2008-09-27T07:23:51.933 回答
23

我知道在这一天给出答案已经很晚了,但我发现没有一个答案对我来说像我自己的解决方案那样有用。获取从 CWD 到 bin 文件夹的路径的一种非常简单的方法是:

int main(int argc, char* argv[])
{
    std::string argv_str(argv[0]);
    std::string base = argv_str.substr(0, argv_str.find_last_of("/"));
}

您现在可以将其用作相对路径的基础。所以例如我有这个目录结构:

main
  ----> test
  ----> src
  ----> bin

我想将我的源代码编译到 bin 并写一个日志来测试我可以将这一行添加到我的代码中。

std::string pathToWrite = base + "/../test/test.log";

我已经使用完整路径、别名等在 Linux 上尝试了这种方法,并且效果很好。

笔记:

如果您在 Windows 上,则应使用“\”作为文件分隔符,而不是“/”。你也必须逃避这个,例如:

std::string base = argv[0].substr(0, argv[0].find_last_of("\\"));

我认为这应该可行,但尚未测试,因此如果可行,请发表评论,如果不可行,请进行修复。

于 2015-08-15T10:58:58.727 回答
21

文件系统 TS现在是一个标准(gcc 5.3+ 和 clang 3.9+ 支持),所以你可以使用current_path()它的函数:

std::string path = std::experimental::filesystem::current_path();

在 gcc (5.3+) 中包含 Filesystem 您需要使用:

#include <experimental/filesystem>

并将您的代码与-lstdc++fs标志链接。

如果您想将 Filesystem 与 Microsoft Visual Studio 一起使用,请阅读此.

于 2016-01-16T22:20:02.357 回答
10

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

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

此外,您应该澄清您想要当前目录还是程序图像/可执行文件所在的目录。就目前而言,您的问题在这一点上有点模棱两可。

于 2008-09-27T07:22:03.107 回答
10

在 Windows 上,最简单的方法是使用_get_pgmptr函数 instdlib.h获取指向字符串的指针,该字符串表示可执行文件的绝对路径,包括可执行文件的名称。

char* path;
_get_pgmptr(&path);
printf(path); // Example output: C:/Projects/Hello/World.exe
于 2013-06-02T22:03:48.000 回答
8

也许将当前工作目录与 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

于 2008-09-27T07:32:09.573 回答
7

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

于 2008-09-27T07:21:01.223 回答
6

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

另外请注意,当前目录和包含可执行文件的目录是两个不同的东西,因此 getcwd() 也无济于事。

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

于 2008-09-27T08:17:00.387 回答
4

只是我的两分钱,但以下代码不能在 C++17 中可移植地工作吗?

#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;

int main(int argc, char* argv[])
{
    std::cout << "Path is " << fs::path(argv[0]).parent_path() << '\n';
}

似乎至少在 Linux 上对我有用。

基于之前的想法,我现在有:

std::filesystem::path prepend_exe_path(const std::string& filename, const std::string& exe_path = "");

通过实施:

fs::path prepend_exe_path(const std::string& filename, const std::string& exe_path)
{
    static auto exe_parent_path = fs::path(exe_path).parent_path();
    return exe_parent_path / filename;
}

和初始化技巧main()

(void) prepend_exe_path("", argv[0]);

感谢@Sam Redway 的 argv[0] 想法。当然,我知道当 OP 提出这个问题时,C++17 已经存在很多年了。

于 2020-03-22T19:44:23.713 回答
3

只是为了迟来的堆积在这里,...

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

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

于 2010-01-27T23:50:14.493 回答
3

对于控制台上的 Windows 系统,您可以使用 system( dir) 命令。控制台为您提供有关目录等的信息。dircmd. 但是对于类 Unix 系统,我不知道……如果运行此命令,请阅读 bash 命令。ls不显示目录...

例子:

int main()
{
    system("dir");
    system("pause"); //this wait for Enter-key-press;
    return 0;
}
于 2013-06-10T16:52:50.567 回答
3
#include <windows.h>
using namespace std;

// The directory path returned by native GetCurrentDirectory() no end backslash
string getCurrentDirectoryOnWindows()
{
    const unsigned long maxDir = 260;
    char currentDir[maxDir];
    GetCurrentDirectory(maxDir, currentDir);
    return string(currentDir);
}
于 2014-02-19T17:15:35.623 回答
2

从 C++11 开始,使用实验文件系统,C++14-C++17 以及使用官方文件系统。

应用程序.h:

#pragma once

//
// https://en.cppreference.com/w/User:D41D8CD98F/feature_testing_macros
//
#ifdef __cpp_lib_filesystem
#include <filesystem>
#else
#include <experimental/filesystem>

namespace std {
    namespace filesystem = experimental::filesystem;
}
#endif

std::filesystem::path getexepath();

应用程序.cpp:

#include "application.h"
#ifdef _WIN32
#include <windows.h>    //GetModuleFileNameW
#else
#include <limits.h>
#include <unistd.h>     //readlink
#endif

std::filesystem::path getexepath()
{
#ifdef _WIN32
    wchar_t path[MAX_PATH] = { 0 };
    GetModuleFileNameW(NULL, path, MAX_PATH);
    return path;
#else
    char result[PATH_MAX];
    ssize_t count = readlink("/proc/self/exe", result, PATH_MAX);
    return std::string(result, (count > 0) ? count : 0);
#endif
}
于 2019-06-10T12:22:04.833 回答
1

对于相对路径,这就是我所做的。我知道这个问题的年龄,我只是想提供一个在大多数情况下都有效的更简单的答案:

假设您有这样的路径:

"path/to/file/folder"

出于某种原因,在 Eclipse 中制作的 Linux 构建的可执行文件可以正常工作。但是,如果给定这样的路径,Windows 会变得非常困惑!

如上所述,有几种方法可以获取可执行文件的当前路径,但我发现在大多数情况下最简单的方法是将其附加到路径的前面:

"./path/to/file/folder"

只需添加“./”即可让您排序!:) 然后你可以从你想要的任何目录开始加载,只要它与可执行文件本身一起。

编辑:如果您尝试从 code::blocks 启动可执行文件,如果那是正在使用的开发环境,这将不起作用,因为某种原因,code::blocks 不能正确加载东西......:D

EDIT2:我发现的一些新东西是,如果您在代码中指定像这样的静态路径(假设 Example.data 是您需要加载的东西):

"resources/Example.data"

如果您然后从实际目录启动您的应用程序(或在 Windows 中,您创建一个快捷方式,并将工作目录设置为您的应用程序目录),那么它将像这样工作。在调试与缺少资源/文件路径相关的问题时请记住这一点。(特别是在从 IDE 启动构建 exe 时设置错误工作目录的 IDE 中)

于 2015-04-21T05:21:19.423 回答
1

图书馆解决方案(虽然我知道这不是要求)。如果你碰巧使用 Qt: QCoreApplication::applicationDirPath()

于 2017-10-04T09:38:03.557 回答
1

当前 .exe 的路径


#include <Windows.h>

std::wstring getexepathW()
{
    wchar_t result[MAX_PATH];
    return std::wstring(result, GetModuleFileNameW(NULL, result, MAX_PATH));
}

std::wcout << getexepathW() << std::endl;

//  -------- OR --------

std::string getexepathA()
{
    char result[MAX_PATH];
    return std::string(result, GetModuleFileNameA(NULL, result, MAX_PATH));
}

std::cout << getexepathA() << std::endl;

于 2020-12-28T07:36:08.220 回答
0

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

在 Windows 上,您可以使用_getcwd(),因为getcwd()的使用已被弃用。

对于标准库,如果 Boost 对您来说足够标准,我会建议 Boost::filesystem,但他们似乎已经从提案中删除了路径规范化。您可能必须等到TR2 随时可用,才能获得完全标准的解决方案。

于 2008-09-27T07:31:38.717 回答
0

Boost Filesystem's 的initial_path()行为类似于 POSIX's getcwd(),并且您自己也不需要,但附加argv[0]到它们中的任何一个都应该这样做。

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

envp我之前使用(第三个参数main()在 Linux 上工作但在 Windows 上似乎不工作) 编写了一个解决方案,所以我基本上推荐与其他人之前所做的相同的解决方案,但额外解释了为什么它实际上是正确的即使结果并不漂亮。

于 2008-09-28T04:28:35.823 回答
0

正如Minok 所提到的,没有指定 ini C 标准或 C++ 标准的此类功能。这被认为是纯粹的操作系统特定功能,例如在 POSIX 标准中指定。

Thorsten79给出了很好的建议,它是 Boost.Filesystem 库。但是,如果您不想为您的程序提供任何二进制形式的链接时依赖项,这可能会带来不便。

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

于 2010-01-28T00:26:18.837 回答
0

progname的 linux bash 命令 将报告程序的路径。

即使可以从您的程序中发出 which 命令并将输出定向到 tmp 文件,并且程序随后读取该 tmp 文件,它也不会告诉您该程序是否正在执行。它只告诉您具有该名称的程序所在的位置。

需要的是获取您的进程 ID 号,并解析出名称的路径

在我的程序中,我想知道程序是从用户的 bin 目录还是从路径中的另一个目录或 /usr/bin 执行的。/usr/bin 将包含支持的版本。我的感觉是,在 Linux 中有一种可移植的解决方案。

于 2016-08-22T15:46:54.233 回答
0

realpath()像这样使用stdlib.h

char *working_dir_path = realpath(".", NULL);
于 2019-05-09T13:15:54.900 回答
0

以下对我来说在 macOS 10.15.7 上运行良好

brew install boost

主文件

#include <iostream>
#include <boost/filesystem.hpp>

int main(int argc, char* argv[]){
  boost::filesystem::path p{argv[0]};
  p = absolute(p).parent_path();
  std::cout << p << std::endl;
  return 0;
}

编译

g++ -Wall -std=c++11 -l boost_filesystem main.cpp
于 2022-02-27T00:22:02.010 回答