"argv [0] =可执行文件名称"是一个公认的标准还是只是一个共同的约定?

Mik*_*kes 92 c c++ standards argv

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

pax*_*blo 107

猜测(即使是有教育意义的猜测)很有趣,但你确实需要去标准文件.例如,ISO C11陈述(我的重点):

如果值argc大于零,则指向的字符串argv[0] 表示程序名称; argv[0][0]如果程序名不能从主机环境获得,则应为空字符.

所以不,如果该名称可用,它只是程序名称."代表"程序名称,不一定程序名称.之前的部分说明:

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

这与之前的标准C99相同,并且意味着即使这些也不是由标准决定的 - 它完全取决于实现.

这意味着,节目名称可以是空的,如果主机环境如果主机环境提供它,别的提供的,规定"任何东西"在某种程度上代表了程序名称.在我更悲惨的时刻,我会考虑将其翻译成斯瓦希里语,通过替换密码运行它,然后以反向字节顺序存储它:-).

但是,实现定义确实在ISO标准具有特定含义 - 实现必须记录其工作原理.因此,即使UNIX,它可以把任何东西它喜欢到argv[0]exec家人通话的,有(并执行)文件就可以了.

  • 这个问题根本没有提到UNIX*.这是一个简单明了的C问题,因此ISO C是参考文献.程序名称是标准中定义的实现,因此一个实现可以自由地做它想要的东西,包括允许那些不是实际名称的东西 - 我以为我在倒数第二句中明确说明了. (4认同)
  • @caf,这是对的.我已经看到它持有程序的完整路径('/ progpath/prog'),只是文件名('prog'),稍微修改过的名称('-prog'),描述性名称(' prog - 一个用于编程的程序')而没有任何东西('').实现必须定义它所拥有的内容,但这是所有标准要求. (4认同)
  • 这可能是标准,但是unix根本不执行它,你不能指望它. (3认同)
  • 感谢大家!一个(看似)简单问题的精彩讨论。尽管Richard的答案对* nix操作系统有效,但我选择paxdiablo的答案是因为我对特定OS的行为不太感兴趣,而主要是对是否存在公认的标准感兴趣。(如果您很好奇:在原始问题的上下文中-我没有操作系统。我正在编写代码来为加载到嵌入式设备上的可执行文件构建原始argc / argv缓冲区,并且需要知道我应该怎么做与argv [0])。为StackOverflow +1了不起! (3认同)
  • Pax,我没有投票给你,并且不赞成那些做过的人,因为这个回答是权威的,因为它可以*得到.但我确实认为`argv [0]的价值的不可靠性适用于现实世界中的编程. (2认同)

Ric*_*ton 45

*nix具有exec*()呼叫的类型系统下,argv[0]将是呼叫者在呼叫中放入的任何argv0地方exec*().

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

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

  • 这是比上面的paxdiablo更好的答案.该标准只是将其称为"程序名称",但据我所知,这并不是强制执行的.Unix内核将传递给execve()的字符串统一传递给子进程. (4认同)
  • C标准的含义有限,因为它不知道'execve()'等.POSIX标准(http://www.opengroup.org/onlinepubs/9699919799/functions/execve.html)有更多说 - 明确表示argv [0]中的内容是在执行'execve()'(或相关)系统调用的过程中. (4认同)

小智 8

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

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

所以不,至少在标准方面,它无法得到保证.

  • 我假设这是空终止的多字节字符串? (4认同)

Gre*_*osz 7

ISO-IEC 9899 规定:

5.1.2.2.1 程序启动

如果 的值argc大于零,则指向的字符串argv[0]代表程序名;argv[0][0]如果程序名在宿主环境中不可用,则应为空字符。如果 的值argc大于 1,则argv[1]通过指向的字符串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) */
Run Code Online (Sandbox Code Playgroud)

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

  • `/proc/self/path/a.out` 符号链接可能在 Solaris 10 及更高版本上可用。 (2认同)

Cir*_*四事件 5

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

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

Runnable 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);
}
Run Code Online (Sandbox Code Playgroud)

公元前

#include <stdio.h>

int main(int argc, char **argv) {
    puts(argv[0]);
}
Run Code Online (Sandbox Code Playgroud)

然后:

gcc a.c -o a.out
gcc b.c -o b.out
./a.out
Run Code Online (Sandbox Code Playgroud)

给出:

yada yada
Run Code Online (Sandbox Code Playgroud)

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

在 Ubuntu 16.10 上测试。