“argv =可执行的名称”是一个可接受的标准还是一个通用的约定?

在C或C ++应用程序中将parameter passing给main()时, argv[0]始终是可执行文件的名称? 或者这只是一个共同的约定,并不能保证100%的时间是真实的?

猜测(甚至受过教育的猜测)很有趣,但是你确实需要去标准文件。 例如,ISO C11州(我强调):

如果argc的值大于零,则argv[0]指向的string表示程序名称; 如果程序名称在主机环境中不可用,则argv[0][0]应为空字符。

所以,不,只有程序名称,如果这个名字是可用的。“代表”程序名称,不一定程序名称。 之前的部分说:

如果argc的值大于零,则argv[0]argv[argc-1]包含的数组成员应该包含指向string的指针,这些string在程序启动之前由主机环境给出实现定义的值。

这与之前的标准C99没有任何变化,意味着即使这些不是由标准决定的 – 完全取决于实施。

这意味着,如果主机环境没有提供程序名称,则程序名称可以是空的,如果主机环境确实提供程序名称,则程序名称可以是空的,只要“其他”以某种方式代表程序名称。 在我更悲观的时刻,我会考虑将其翻译成斯瓦希里语,通过replace密码运行,然后以反向字节顺序存储:-)。

但是,实现定义在ISO标准中确实具有特定含义 – 实现必须logging它的工作原理。 因此,即使是UNIX,它可以把任何它喜欢的东西与调用exec系列argv[0] ,必须(并)logging它。

在带有exec*()调用的*nixtypes系统下, argv[0]将成为调用者放入exec*()调用中的argv0位置的内容。

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

但是一个stream氓Unix程序可以调用exec()并使argv[0]成为它所喜欢的任何东西,所以不pipeC标准说什么,你都不能指望这100%的时间。

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

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

所以不行,至less按照标准是不能保证的。

该页面指出:

元素argv [0]通常包含程序的名称,但是这不应该依赖 – 反正程序不知道自己的名字是不寻常的!

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

你会注意到argv [0]是程序本身的path和名字。 这允许程序发现关于它自己的信息。 它还增加了一个程序参数数组,所以在获取命令行参数时常见的错误是当您想要argv [1]时抓取argv [0]。

ISO-IEC 9899规定:

5.1.2.2.1程序启动

如果argc的值大于零, argv[0]指向的string表示程序名; 如果程序名称在主机环境中不可用,则argv[0][0]应为空字符。 如果argc的值大于1,则argv[1]argv[argc-1]指向的string表示程序参数

我也用过:

 #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) */ 

然后你只需要parsingstring来从path中提取可执行文件的名字。

我不确定这是一个近乎普遍的惯例还是一个标准,但是你应该遵守这个惯例。 不过,我从来没有见过它在Unix和类Unix系统之外被利用。 在Unix环境中(特别是在过去的时代),根据调用的名称,程序可能会有明显不同的行为。

编辑:我从其他职位同时看到,有人认为它来自一个特定的标准,但我相信长久以来的惯例早于标准。

可运行的POSIX execve示例,其中argv[0] !=可执行文件名

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

ac

 #define _XOPEN_SOURCE 700 #include <unistd.h> int main(void) { char *argv[] = {"yada yada", NULL}; char *envp[] = {NULL}; execve("b.out", argv, envp); } 

bc

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

然后:

 gcc ac -o a.out gcc bc -o b.out ./a.out 

得到:

 yada yada 

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

  • NULL: 何时可以argv [0]有空?
  • 空: argv [0]是否可以包含空string?

在Ubuntu 16.10上testing