C程序,打印其可执行文件名

假设源代码文件名是test.cpp 。 编译时,它会生成test.exe文件。 当我执行它时,它应该识别它的文件名test.exe并打印它。

我可以使用以下代码获取当前目录中存在的所有文件和目录的列表:

 DIR * directory; struct dirent * direct; direct = readdir(directory); 

但是,如何识别关联的文件名,在这种情况下是"test.exe"

您在构建可执行文件时知道它的名称; 最简单的解决方案是将其嵌入到程序中,使用-D/D选项在命令行上定义宏。

除此之外,通用答案是不可能的:

根据标准

  • argv[0]应该包含用于调用程序的名称(无论这意味着什么)。 哪个好,但1)它甚至不能在Unix下实现,2)在大多数系统中,存在各种别名,这意味着用于调用程序的名称与可执行文件的名称无关。

在Windows下

  • 有一个系统函数GetModuleFileName ,可用于获取可执行文件的路径 。 获得路径后,路径的最后一个元素就是可执行文件的名称。

在Unix下

  • 这根本不可能。 当启动一个新进程时,Unix为可执行文件的路径采用单独的参数,并且最终在argv[0] ,因此它们可能彼此之间没有任何关系。 这一切都取决于谁开始你的过程。 bash会在环境变量"_"放置可执行文件的完整路径,因此您可以使用getenv来获取它。 但这只适用于你的程序是由bash启动的。 在大多数Unices上,你也可以在/proc文件系统中找到它,如果你知道你的方式; 但是这种组织方式因Unix而异。 另请注意,由于硬链接,您可执行文件可能没有一个名称。

真正的问题是你想要这样做的原因。 你想解决的问题是什么?

在main函数中, argv[0]是命令行中可执行文件的名称

 #include  int main(int argc, char ** argv) { printf("%s", argv[0]); return 0; } 

现场演示

这将打印命令名称,即相对于当前工作目录的目录,以及可执行文件名称(如果可用,这是不可保证的)要获取当前工作目录,请使用getcwd()标准库C函数。

argv[0]的命令路径中提取文件名是特定于平台的:unix使用斜杠’ / ‘,windows允许混合使用斜杠/和反斜杠\ ,并且任何其他平台都可以使用任何其他路径分隔符。 从路径中提取文件名需要跨平台库,例如Qt或Boost 。 在POSIX环境中 ,可以使用basename。

 #include  int main(int argc, char *argv[]) { printf("%s\n", argv[0]); return 0; } 

请注意,您的程序可以启动为:

 /home/user/./app 

在这种情况下,您可以使用strrchr获取名称:

 #include  #include  int main(int argc, char *argv[]) { char *appname; appname = strrchr(argv[0], '/'); /* '\\' on Windows */ printf("%s\n", appname ? ++appname : argv[0]); return 0; } 

在Linux系统中,我认为你也可以使用basename(char *path);libgen.h ,尝试$ man basename

打印NAME,删除任何前导目录组件。 如果指定,还删除尾随的SUFFIX。

我试过它:

 // filename.c #include #include #include int main(int argc, char* argv[]){ char* exe_name = basename(argv[0]); printf(" Executable Name: %s", exe_name); printf("\n"); return EXIT_SUCCESS; } 

观察,编译和测试为:

 taxspanner@:~$ ls filename.c filename.c taxspanner@:~$ gcc -std=gnu99 -Wall -pedantic filename.c -o filename taxspanner@:~$ ls filename* filename filename.c taxspanner@:~$ 

现在在当前目录中运行它:

 taxspanner@:~$ ./filename Executable Name: filename 

使用绝对路径:

 taxspanner@:~$ pwd /home/taxspanner taxspanner@:~$ /home/taxspanner/filename Executable Name: filename 

相对路径:

 taxspanner@:~$ cd study/divide-5/ taxspanner@:~/study/divide-5$ pwd /home/taxspanner/study/divide-5 taxspanner@:~/study/divide-5$ ls ../../filename* ../../filename ../../filename.c taxspanner@:~/study/divide-5$ ../../filename Executable Name: filename taxspanner@:~/study/divide-5$ 

再试一次带有后缀的可执行文件名:

 taxspanner@:~$ gcc -std=gnu99 -Wall -pedantic filename.c -o filename.out taxspanner@:~$ ./filename.out Executable Name: filename.out taxspanner@:~$ cd study/divide-5/ taxspanner@:~/study/divide-5$ ../../filename.out Executable Name: filename.out 

使用时要小心 : dirname()basename()可以修改path的内容,因此在调用其中一个函数时可能需要传递一个副本

试试看!!

在Linux上具体:

你可以使用proc(5)和/proc/self/exe符号链接,所以使用readlink(2) 。 一旦你这样做,你可以在获得的符号链接上使用basename(3)或realpath(3) 。

但是,请注意程序可能并不总是具有文件路径。 它可能有多个文件路径(例如/bin/rbash/bin/bash的符号链接,并且shell进程在作为rbashbash调用时表现不同)。 有时,给定文件(实际上是inode ,请参阅inode(7) )有几个硬链接。 在奇怪的情况下,没有。 并且可能会发生程序执行(2) -ed然后使用unlink(2) (可能来自计划在您之前运行的另一个进程)等删除。

(顺便说一下,你的问题是特定于操作系统的; readdir(3)是POSIX,有些操作系统甚至没有目录,而且读取器没有被C11标准提及;请查阅n1570 )

我尝试了以下(病态) ./selfremove程序(在我的/home/basile/tmp/目录中)删除自己的二进制文件:

  // file selfremove.c #include  #include  #include  #include  int main (int argc, char **argv) { char selfpath[128]; memset (selfpath, 0, sizeof (selfpath)); if (readlink ("/proc/self/exe", selfpath, sizeof (selfpath) - 1) < 0) { perror ("first readlink"); exit (EXIT_FAILURE); }; printf ("initial /proc/self/exe -> %s\n", selfpath); if (unlink (argv[0])) { fprintf (stderr, "unlink %s: %m\n", argv[0]); exit (EXIT_FAILURE); }; printf ("%s unlinked\n", argv[0]); if (readlink ("/proc/self/exe", selfpath, sizeof (selfpath) - 1) < 0) { perror ("second readlink"); exit (EXIT_FAILURE); }; printf ("final /proc/self/exe -> %s\n", selfpath); return 0; } 

它工作正常,内核正在构建一个* (deleted)符号链接(因为反向编码器可能会将可执行文件重命名为selfremove (deleted) ,因此内核添加后缀只是一个指示….):

  % ./selfremove initial /proc/self/exe -> /home/basile/tmp/selfremove ./selfremove unlinked final /proc/self/exe -> /home/basile/tmp/selfremove (deleted) 

因此,即使使用/proc/self/exe您也无法始终信任结果。

如果你假设你的程序已被某个shell(或类似程序执行execvp(3) ) execve(2) – 并且情况并非总是如此 – 那么可能已经使用了PATH变量 (并从你的main搜索如果它没有/ ),则为argv[0] 。 您可以使用getenv(3)作为getenv("PATH")从您的环境中获取它(有关更多信息,请参阅environ(7) )。 通常设置和使用$PATH ,但它们也是病态案例。

所以通常没有办法可靠地打印自己的可执行文件(正如我的病态selfremove.c演示)。 在大多数情况下,您可以找到它(例如,通过/proc/self/exereadlink ,或通过使用argv[0]$PATH搜索)。