117

main()在 C 或 C++ 应用程序中传递参数时,将argv[0]始终是可执行文件的名称?或者这只是一个常见的约定,不能保证 100% 的时间是正确的?

4

8 回答 8

133

猜测(甚至是有根据的猜测)很有趣,但您确实需要查看标准文档才能确定。例如,ISO C11 声明(我的重点):

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

所以不,如果该名称可用,它只是程序名称。而它“代表”的是程序名,不一定程序名。之前的部分指出:

如果 的值argc大于零,则argv[0]通过argv[argc-1]inclusive 的数组成员应包含指向字符串的指针,这些指针在程序启动之前由宿主环境赋予实现定义的值。

这与以前的标准 C99 没有变化,这意味着即使是也不是由标准规定的——这完全取决于实现。

这意味着如果主机环境不提供程序名称,则程序名称可以为空,如果主机环境确实提供它,则程序名称可以为空,前提是“其他任何内容”以某种方式表示程序名称。在我更加虐待狂的时刻,我会考虑将其翻译成斯瓦希里语,通过替换密码运行它,然后以相反的字节顺序存储它:-)。

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

于 2010-01-12T17:40:15.863 回答
53

在带有调用的*nix类型系统下,调用者在调用中放入的任何内容都将是。exec*()argv[0]argv0exec*()

shell 使用程序名称的约定,大多数其他程序遵循相同的约定,因此argv[0]通常是程序名称。

但是一个流氓 Unix 程序可以调用exec()并制作argv[0]它喜欢的任何东西,所以无论 C 标准怎么说,你都不能指望这 100% 的时间。

于 2010-01-12T17:40:41.060 回答
9

根据 C++ 标准,第 3.6.1 节:

argv[0] 应该是指向 NTMBS 的初始字符的指针,表示用于调用程序的名称或“”

所以不,它不能保证,至少标准是这样。

于 2010-01-12T17:39:04.527 回答
7

ISO-IEC 9899 规定:

5.1.2.2.1 程序启动

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

我也用过:

#if defined(_WIN32)
  static size_t getExecutablePathName(char* pathName, size_t pathNameCapacity)
  {
    return GetModuleFileNameA(NULL, pathName, (DWORD)pathNameCapacity);
  }
#elif defined(__linux__) /* elif of: #if defined(_WIN32) */
  #include <unistd.h>
  static size_t getExecutablePathName(char* pathName, size_t pathNameCapacity)
  {
    size_t pathNameSize = readlink("/proc/self/exe", pathName, pathNameCapacity - 1);
    pathName[pathNameSize] = '\0';
    return pathNameSize;
  }
#elif defined(__APPLE__) /* elif of: #elif defined(__linux__) */
  #include <mach-o/dyld.h>
  static size_t getExecutablePathName(char* pathName, size_t pathNameCapacity)
  {
    uint32_t pathNameSize = 0;

    _NSGetExecutablePath(NULL, &pathNameSize);

    if (pathNameSize > pathNameCapacity)
      pathNameSize = pathNameCapacity;

    if (!_NSGetExecutablePath(pathName, &pathNameSize))
    {
      char real[PATH_MAX];

      if (realpath(pathName, real) != NULL)
      {
        pathNameSize = strlen(real);
        strncpy(pathName, real, pathNameSize);
      }

      return pathNameSize;
    }

    return 0;
  }
#else /* else of: #elif defined(__APPLE__) */
  #error provide your own implementation
#endif /* end of: #if defined(_WIN32) */

然后您只需解析字符串即可从路径中提取可执行文件名称。

于 2010-01-12T17:42:40.523 回答
6

具有argv[0] !=可执行名称的应用程序

另请参阅:https ://unix.stackexchange.com/questions/315812/why-does-argv-include-the-program-name/315817

可执行名称的可运行 POSIXexecve示例argv[0] !=

其他人提到exec,但这是一个可运行的示例。

交流

#define _XOPEN_SOURCE 700
#include <unistd.h>

int main(void) {
    char *argv[] = {"yada yada", NULL};
    char *envp[] = {NULL};
    execve("b.out", argv, envp);
}

公元前

#include <stdio.h>

int main(int argc, char **argv) {
    puts(argv[0]);
}

然后:

gcc a.c -o a.out
gcc b.c -o b.out
./a.out

给出:

yada yada

是的,argv[0]也可以是:

在 Ubuntu 16.10 上测试。

于 2017-02-17T06:46:50.870 回答
3

该页面指出:

元素 argv[0] 通常包含程序的名称,但这不应该被依赖 - 无论如何,程序不知道自己的名称是不寻常的!

但是,其他页面似乎支持它始终是可执行文件的名称这一事实。条规定:

您会注意到 argv[0] 是程序本身的路径和名称。这允许程序发现有关自身的信息。它还向程序参数数组添加了一个,因此在获取命令行参数时的一个常见错误是在需要 argv[1] 时抓取 argv[0]。

于 2010-01-12T17:33:57.173 回答
3

我不确定它是几乎普遍的约定还是标准,但无论哪种方式,您都应该遵守它。不过,我从未见过它在 Unix 和类 Unix 系统之外被利用。在 Unix 环境中 - 尤其是在过去 - 程序可能具有显着不同的行为,具体取决于调用它们的名称。

已编辑:我同时从其他帖子中看到有人将其识别为来自特定标准,但我确信约定早于标准。

于 2010-01-12T17:43:25.817 回答
0

如果您通过 Workbench 启动 Amiga 程序,则不会设置 argv[0],只能通过 CLI 设置。

于 2018-11-23T16:03:41.307 回答