“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*()
调用的*nix
types系统下, 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