【问题标题】:Without access to argv[0], how do I get the program name?无法访问 argv[0],如何获取程序名称?
【发布时间】:2011-05-01 04:58:55
【问题描述】:

我知道程序名称是作为第一个参数传递的,下一个简单示例会将其打印到标准输出:

#include <iostream>
int main ( int argc, char *argv[] )
{
  std::cout<<argv[0]<<std::endl;
}

有获取程序名的函数吗?

编辑

我从 shell 启动程序,上面的代码总是会打印程序名称(我使用的是 fedora 9,但我确信它可以在其他发行版中使用)。

我发现 /proc/self/ 目录可能包含我要查找的内容,但我无法在该目录中找到确切的内容。

【问题讨论】:

  • 什么意思?您刚才说您知道“程序名称”作为第一个参数传递...那您还需要什么?
  • @mt_serg, @Kelsey Rider 如果你仔细阅读这个问题,这个问题很简单,它说“argv[0] 用于查找程序名称,但是是否有另一个函数来获取程序名称?”。没有冒犯:)
  • @Searock 没有冒犯,只是误解。和平:-)
  • 从图书馆的角度来看,这个问题很有意义。

标签: c++ c linux command-line-arguments


【解决方案1】:

不,没有这样的功能。 Linux 将程序名称存储在__progname 中,但这不是公共接口。如果您想将其用于警告/错误消息,请使用 err(3) 函数。

如果要运行程序的完整路径,请在/proc/self/exe上调用readlink

char *program_path()
{
    char *path = malloc(PATH_MAX);
    if (path != NULL) {
        if (readlink("/proc/self/exe", path, PATH_MAX) == -1) {
            free(path);
            path = NULL;
        }
    }
    return path;
}

(我相信__progname 设置为argv[0] 的基本名称。请查看glibc 源以确定。)

【讨论】:

  • 使用 readlink 可以正常工作。谢谢你。我也试过 __progname,但它没有编译。不知道我必须包括什么才能使它工作。
  • 你不应该使用__progname,因为它没有被记录并且仅供err(3)函数内部使用。 (如果你想作弊,用extern const char *__progname;声明它,但实际上,你不想作弊。)
  • /proc/self/cmdline 应该给出完整的参数集,并用空格分隔,传递给该程序。
【解决方案2】:

这不能保证。

通常,argv[0] 保存可执行文件名称,但可以使用 execve 调用您的可执行文件并将其设置为其他名称。

一句话:不要依赖这个。

【讨论】:

  • 此外,至少在 Windows 上,argv[0] 可能包含完整路径以及带有扩展名的可执行文件名。
  • argv[0] 始终是我认为的程序名称。
  • @Chubsdad:ereOn 刚刚指出这可能不是真的。所以不,它并不总是程序的名称。
  • @Chubsdad:如果您知道,请写下您自己的答案。如果你只是想,那就去查一下或等待知道的人回答。目前你错了(还有那些跟着你投票赞成你的评论的愚蠢的羊)。
  • 比这更糟糕。在带有 bash 的 Linux 上,这个参数是面向用户的: bash -c 'exec -a"The beautiful program name that is in argv[0]" ./executable'
【解决方案3】:

GLIBC 专用解决方案:

#include <errno.h>
...
fprintf(stderr, "Program name is %s\n", program_invocation_name);

来自man invocation_name

program_invocation_name 包含用于调用调用程序的名称。这与main()argv[0]的值相同,区别在于program_invocation_name的作用域是全局的。

program_invocation_short_name 包含用于调用调用程序的 name 的 basename 组件。也就是说,它与 program_invocation_name 的值相同,所有文本都被删除,直到并包括最后的斜杠 (/),如果有的话。

【讨论】:

【解决方案4】:

不,它完全取决于父程序放在那里的内容。

exec 系列函数允许可执行文件名称与传入的参数完全不同,ISO C 标准支持这一点。

如果argc的值大于零,则argv[0]指向的字符串代表程序名;如果主机环境中没有程序名,则 argv[0][0] 应为空字符。

所以不,如果名称可用,它只是程序名称。之前的部分指出:

如果 argc 的值大于零,则数组成员 argv[0] 到 argv[argc-1] 应包含指向字符串的指针,这些指针由程序启动前的宿主环境。

(我的斜体)。

因此,即使它们的值也不是由标准规定的,完全取决于实施。这意味着如果宿主环境不提供程序名称,则程序名称可以为空,如果宿主环境提供,则程序名称可以为空。

但是,实施定义在 ISO 标准中具有特定含义 - 实施必须记录其工作方式。因此,即使是 UNIX,它可以通过 exec 系列调用将任何它喜欢的东西放入 argv[0],也必须(并且确实)记录它。

类似地(感谢 Chubsdad),C++03 声明:

"如果 argc 不为零,则这些参数应在 argv[0] 到 argv[argc-1] 中作为指向空终止多字节字符串 (NTMBS) (17.3.2.1.3.2) 和 argv[ 0] 应该是指向 NTMBS 的初始字符的指针,表示用于调用程序的名称或“”。

因此,即使在那里,argv[0] 也可能不包含任何内容,即使包含,“代表名称”也是一个非常模糊的要求。它不必是可执行文件的完整路径名,甚至不必包含用于调用它的命令


在 Linux 下的另一种方法是使用 proc 文件系统。我认为/proc/self/exe 是指向可执行文件的链接。

维基百科有一个 procfs 文件系统的条目,里面有很多好东西。

【讨论】:

  • C++ 标准 (03) 规定 - “如果 argc 不为零,则应在 argv[0] 到 argv[argc-1] 中提供这些参数,作为指向以空字符结尾的多字节字符串的初始字符的指针(NTMBS) (17.3.2.1.3.2) 和 argv[0] 应是指向 NTMBS 的初始字符的指针,该字符表示用于调用程序的名称或“”。
  • 那么,C 和 C++ 的行为可能不同吗?
  • 我不这么认为,@Chubsdad:这似乎与 C 标准没什么不同。 argv[0] 可以代表程序名称或为空。还要注意黄鼠狼单词“代表名称” - 这绝不是可执行文件的完整路径,甚至是部分匹配。也许我很愤世嫉俗,但字符串 "A delay program" 将完全代表 /bin/sleep :-)
  • @Chubsdad:我相信这与 pax 引用的内容 100% 相同。
  • 允许软链接指向已删除的文件。事实上,它可以指向任何东西。它们在 /proc/*/fd/ 中有很多指向文件系统中根本不存在的“[socket:1984]”或“[pipe:6116]”。
【解决方案5】:

您可以使用 getpid() 确定进程的 pid,然后使用标准 I/O 工具检查 /proc/[pid number] 的内容。

【讨论】:

  • 这是我想做的,但程序名称是什么?
  • 看我的回答。你不需要getpid
  • 您可以通过在 /proc/[pid]/exe 或(甚至更好)/proc/self/exe 上调用 readlink() 来获得所需的内容。虽然不是 100% 确定。
  • /proc/self 是当前进程的 /proc 条目的半魔法名称。不需要getpid()。但是 +1 推荐 /proc。
【解决方案6】:

如果你使用 GLib,你可以使用函数g_get_prgname()。在 Win32 上它调用 GetModuleFileNameW(),但在其他所有东西上它似乎返回 NULL。

【讨论】:

  • 当您将 g_option_context_parse() 与 argv[0] 一起用于非 Win32 平台时,似乎已设置好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-03-17
  • 1970-01-01
  • 2011-09-09
  • 2019-09-19
  • 2012-09-05
  • 1970-01-01
  • 2017-02-27
相关资源
最近更新 更多