如何在C++中获取当前运行可执行文件的文件名

23

我想获取当前进程的完整路径。

我使用 _getcwd 来获取当前工作目录。但是它不包括文件名称。

如何获取文件名,比如: filename.exe


1
通常是命令行应用程序的第0个参数。 - ssube
1
尝试使用参数0,它应该在那里。 - Markus Mikkolainen
此源将提供帮助 https://dev59.com/uXI_5IYBdhLWcg3wF_B3 - sancelot
8个回答

33

argv[0]在你的主函数中代表你的文件名。

一个简单的代码片段:

#include<stdio.h>
int main(int argc, char** argv)
{
    //access argv[0] here
}

如果你无法访问/更改main()中的代码,可以像这样做:

std::string executable_name()
{
#if defined(PLATFORM_POSIX) || defined(__linux__) //check defines for your setup

    std::string sp;
    std::ifstream("/proc/self/comm") >> sp;
    return sp;

#elif defined(_WIN32)

    char buf[MAX_PATH];
    GetModuleFileNameA(nullptr, buf, MAX_PATH);
    return buf;

#else

    static_assert(false, "unrecognized platform");

#endif
}

5
argv[0] 是用户调用您的程序时使用的名称。如果用户使用了符号链接,则 argv[0] 是符号链接,而不是二进制本身。 - Ken Bloom
1
你可以使用类似这样的代码从argv[0]中提取文件名:http://www.cplusplus.com/forum/beginner/1962/#msg7180 - Carl
我使用 int WINAPI WinMain() 来展示如何通过这种方式完成。 - Phat Tran
我该如何对一个dll文件执行相同的操作? - Ahmed Can Unbay

17

在Windows上,您可以使用:

TCHAR szExeFileName[MAX_PATH]; 
GetModuleFileName(NULL, szExeFileName, MAX_PATH);

szExeFileName将包含完整的路径和可执行文件名。

[编辑]

为了更具可移植性,可以使用argv[0]或其他一些平台特定的代码。您可以在此处找到这种方法:https://github.com/mirror/boost/blob/master/libs/log/src/process_name.cpp


1
这不是可移植的。 - sancelot
1
@sancelot,没有可移植的代码来完成这个任务。在评论中,OP要求使用win32平台,因此给出了这个答案。另外,在Windows下,并不是所有应用程序类型都可以访问argv [0]。顺便说一句,我已经添加了一些提示,以便以可移植的方式实现它。 - marcinj

9
在Linux上,你的二进制文件名是/proc/self/exe符号链接的目标位置。你可以使用readlink系统调用来查找符号链接的目标位置。
请注意,这告诉你二进制文件实际存储在磁盘上的位置,而不仅仅是用户用于启动程序的命令。

1
@SeçkinSavaşçı,我想GetModuleFileName可以解决问题。 - chris

6

以下是使用boost(https://www.boost.org/)的跨平台方法:

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

int main( int argc, char **argv ) {

    std::cout << "hello world, this is [" << boost::dll::program_location().filename().string() << "]" << std::endl;

    std::cout << "or [" << boost::dll::program_location().string() << "] if you're not into the whole brevity thing." << std::endl;

    return 0;
}

通过编译生成

g++ -o hello_world hello_world.cpp -lboost_filesystem -lboost_system -ldl

输出结果

hello world, this is [hello_world]
or [/home/gjvc/tmp/hello_world] if you're not into the whole brevity thing.

4

正如其他人提到的那样,你的可执行文件的名称包含在argv[0]中。如果需要,你可以:

cout << argv[0] << endl;

如果您需要可执行文件的源代码文件名,C++有一个预定义的宏可以使用:__FILE__
cout << __FILE__ << endl;

点击这里,并滚动到“预定义宏名称”


3

2
在Linux(POSIX?)中,有一个名为_的环境变量,其中包含当前进程。
$ echo $_
echo

在C ++中
#include <stdlib.h>     /* getenv */
#include<iostream>
int main(){
    std::cout << getenv("_") << '\n';
    return 0;
}

编译
$ c++ a.cpp -o a.out
$ ./a.out

打印 ./a.out (或者是执行的任何一行,包括路径)。

这种方法比其他方法有一定的优势,它可以全局读取(不需要传递 argv[0])并且不需要文件处理。


这在我的Linux系统上对我不起作用。它打印出shell的pid和路径,而不是当前进程的名称。但是,如果我通过system调用另一个程序,那么子进程将具有正确的名称。这似乎在不同的Unix变体中略有不同。 - Tom Tanner
@TomTanner,这也可能取决于Shell。例如,如果我从不同的目录运行它,则该变量可以包含执行行的相对路径,例如tmp/a.out - alfC

1

通常可以从argv[0]获取可执行文件名:

#include <stdio.h>
int main(int argc, char* argv[])
{
 printf("Running: %s\n", argv[0]);
 return 0;
}

实际上,有一些方法可以让一个应用程序execl()另一个应用程序(或类似的函数)并覆盖此参数。但对于这种类型的应用程序来说,系统改变它仍然是不寻常的。


1
参数 argc 和 argv 的顺序错误,我已经给出了答案 :) - Seçkin Savaşçı
1
你总是可以从argv [0]获取可执行文件名:并非总是如此。调用execl时将argv [0]设置为程序名称是传统惯例。这也是一种可被入侵的惯例。在安全环境中,使argv [0]为空有些成为标准。 - David Hammen
谢谢你们两位。我在我的回答中修复了一些问题,不过现在没有太多需要担心的了。 - E net4

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接