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

在C / C ++中,主函数接收char*types的参数。

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

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

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

argv指向的char*块,实际的字符序列可以在任何地方。 它们将在某个操作系统定义的位置开始,并可能被链接器生成的前导代码复制到堆栈或其他地方。 你必须查看exec()的代码以及链接器生成的汇编程序前导码才能find。

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

这是C标准( n1256 )所说的:

5.1.2.2.1程序启动

2如果声明了, 函数的参数应该遵守以下约束:

  • argc的值应该是非负的。
  • argv [argc]应该是一个空指针。
  • 如果argc的值大于零,则argv [0]argv [argc-1]包含的数组成员应该包含指向string的指针,这些string在程序启动之前由主机环境给出实现定义的值。 其目的是向程序提供在程序启动之前从托pipe环境中的其他地方确定的信息。 如果主机环境不能提供大小写字母的string,则实现应确保string以小写forms接收。
  • 如果argc的值大于零,则argv [0]指向的string表示程序名称 ; 如果程序名称在主机环境中不可用,则argv [0] [0]应为空字符。 如果argc的值大于1,则argv [1]argv [argc-1]指向的string表示程序参数
  • 参数argcargv以及argv数组所指向的string应该可以被程序修改,并在程序启动和程序终止之间保留它们的最后存储的值。

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

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

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

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

然后调用程序员必须提供的函数main(),并将其返回值保存以供稍后(几乎中等)使用。 堆中的结构被释放,并且获得的用于main的退出代码被导出到操作系统。 过程结束。

这些参数与其他function的参数没有区别。 如果体系结构的调用序列需要参数通过堆栈,则它们处于堆栈状态。 如果像x86-64那样的参数进入寄存器,这些也会进入寄存器。

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

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

main()参数的内存可能来自堆栈,可能会被分配到堆栈上(可能使用标准C代码无法使用的技术),也可能使用静态分配的内存,尽pipe这种方法不太可能因为它不够灵活。 该标准确实要求用于argv指向的string的内存是可修改的,并且对这些string所做的修改在整个程序的整个生命周期中都保持不变。

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

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

通常不知道他们在哪里。

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

正如pmg提到的那样,当main被recursion地调用时,取决于参数指向的调用者。 基本上,原来的main调用的答案是一样的,只不过“调用者”是C实现/ OS。

在UNIX-y系统上, argv指向的string, argv指针本身以及进程的初始环境variables几乎总是存储在堆栈的顶部。

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