C / C ++主函数的参数在哪里?

时间:2010-11-16 16:06:49

标签: c++ c parameters location main

在C / C ++中,main函数接收类型为char*的参数。

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

argv是一个char*数组,指向字符串。这些字符串在哪里?它们是在堆,堆栈还是其他地方?

10 个答案:

答案 0 :(得分:31)

它们是编译器魔术,并且依赖于实现。

答案 1 :(得分:28)

以下是C标准(n1256)所说的内容:

5.1.2.2.1程序启动
...
2如果声明它们,功能的参数应遵循以下规则 约束:

  • argc 的值应为非负。

  • argv [argc] 应为空指针。

  • 如果 argc 的值大于零,则数组成员 argv [0] 通过 argv [argc-1] 包含应包含指向字符串的指针 程序启动前主机环境实现定义的值。该 意图是在程序启动之前为程序提供信息 来自托管环境中的其他地方。如果主机环境不具备 为字符串提供大写和小写的字母,实现 应确保琴弦以小写形式收到。

  • 如果 argc 的值大于零,则 argv [0] 指向的字符串 代表程序名称; argv [0] [0] 如果是,则为空字符 程序名称不能从主机环境中获得。如果 argc 的值是 大于一, argv [1] 指向的字符串通过 argv [argc-1] 代表程序参数

  • 参数 argc argv 以及 argv 数组指向的字符串应 可以由程序修改,并在程序之间保留它们最后存储的值 启动和程序终止。

最后一个项目符号是存储字符串值的最有趣的文件。它没有指定堆或堆栈,但它确实要求字符串是可写的并且具有静态范围,这将一些限制放置在字符串内容可能位于的位置。正如其他人所说,具体细节将取决于实施情况。

答案 2 :(得分:16)

它实际上是编译器依赖和操作系统依赖的组合。 main()是一个函数,就像任何其他C函数一样,因此两个参数argcargv的位置将遵循平台上编译器的标准。例如对于大多数针对x86的C编译器,它们将位于返回地址和保存的基指针之上的堆栈上(堆栈向下增长,请记住)。在x86_64上,参数在寄存器中传递,因此argc将在%edi中,argv将在%rsi中。编译器生成的main函数中的代码然后将它们复制到堆栈中,这是后面引用指向的位置。这样寄存器就可以用于来自main的函数调用。

argv指向的char*块,实际的字符序列可以在任何地方。它们将在某个操作系统定义的位置启动,并且可以通过链接器生成到堆栈或其他位置的前导码复制。您将不得不查看exec()的代码和链接器生成的汇编器前导码以查找。

答案 3 :(得分:8)

这个问题的答案是编译器依赖的。这意味着它没有在C标准中处理,因此任何人都可以按照他或她的意愿实现。这是正常的,因为操作系统也没有通用的标准方法来启动流程并完成它们。

让我们想象一个简单的,为什么不是场景。

该进程通过某种机制接收在命令行中写入的参数。然后argc只是一个int,它被编译器作为程序进程(运行时的一部分)的入口点的引导函数推送到堆栈。实际值是从操作系统获得的,并且可以写在堆的内存块中。然后构建argv向量,并将其第一个位置的地址也推入堆栈。

然后调用必须由程序员提供的函数main(),并保存其返回值以供稍后(几乎在中间)使用。释放堆中的结构,并将为main获取的退出代码导出到操作系统。这个过程结束了。

答案 4 :(得分:3)

这些参数与任何其他函数的参数没有什么不同。 如果体系结构的调用序列需要参数通过堆栈,则它们处于堆栈状态。如果,像on,x86-64一些参数进入寄存器,这些参数也会进入寄存器。

答案 5 :(得分:3)

正如许多其他答案所指出的那样,标准未指定编译器实现用于将参数传递给main的精确机制(编译器用于将任何参数传递给函数的机制)。严格地说,编译器甚至不需要传递那些参数中有用的东西,因为这些值是实现定义的。但这些都不是特别有用的答案。

典型的C(或C ++)程序是为所谓的“托管”执行环境编译的(使用函数main(),因为程序的起点是托管环境的要求之一)。要知道的关键是编译器安排事情,以便在操作系统启动可执行文件时,编译器的运行时最初得到控制 - 而不是main()函数。运行时的初始化代码执行必要的初始化,包括为main()的参数分配内存,然后将控制转移到main()

main()的参数的内存可以来自堆,可以在堆栈上分配(可能使用标准C代码不可用的技术),或者可以使用静态分配的内存,尽管这是不太可能的选择只是因为它不太灵活。该标准确实要求用于argv指向的字符串的内存是可修改的,并且对这些字符串的修改在整个程序的生命周期内都会持续存在。

请注意,在执行到main()之前,已经运行了相当多的代码来设置运行程序的环境。

答案 6 :(得分:2)

参数列表是过程环境的一部分,类似于(但不同于)环境变量。

答案 7 :(得分:2)

通常不知道它们在哪里。

#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[]) {
  char **foo;
  char *bar[] = {"foo", "bar"};

  (void)argv; /* avoid unused argv warning */

  foo = malloc(sizeof *foo);
  foo[0] = malloc(42);
  strcpy(foo[0], "forty two");

  /* where is foo located? stack? heap? somewhere else? */
  if (argc != 42) main(42, foo); else return 0;

  /* where is bar located? stack? heap? somewhere else? */
  if (argc != 43) main(43, bar); else return 0;
  /* except for the fact that bar elements
  ** point to unmodifiable strings
  ** this call to main is perfectably reasonable */

  return 0;
  /* please ignore memory leaks, thank you */
}

答案 8 :(得分:2)

pmg所述,当递归调用main时,由参数指向的调用者决定。基本上,main的原始调用的答案是相同的,除了“调用者”是C实现/操作系统。

在UNIX-y系统上,argv指向的字符串,argv指针本身以及进程的初始环境变量几乎总是存储在堆栈的最顶层。

答案 9 :(得分:-1)

虽然您可以访问实际参数,但我认为它们的实际位置根本不重要。