C argv数据的最大大小是什么

可能重复:
关于main函数的命令行参数

我如何确定可以传递到C main的最大数据大小(int argc,char * argv)? 标准中的某个宏是否会定义这个? 数据是否由主进程“拥有”(即我的程序存储此数据)还是由操作系统以某种方式“拥有”,我可以获得指向它的指针?

在POSIX系统中,有一个值ARG_MAX ,在定义,其最小可接受值为_POSIX_ARG_MAX (即4096)。 您可以通过带有SC_ARG_MAX参数的sysconf()函数在运行时发现该值。

它通常是256 KiB。

argv的数据(指针数组和它们指向的字符串)由程序“拥有”。 它们可以修改; 这是否合理取决于你的观点。 你当然不能超出传递给main()函数的范围而不调用未定义的行为。 GNU getopt()函数在没有在环境中设置POSIXLY_CORRECT环境变量的情况下运行时重新组织参数。 您已经有一个指向argv的数据的指针,提供给main()

根据经验,您经常会发现字符串argv[argc-1]结束后的数据实际上是环境的开始。 在一些系统中int main(int argc, char **argv, char **envp)主程序可以写成int main(int argc, char **argv, char **envp) (在C标准附件J,§J.5.1中被认为是扩展),其中envp是相同的值存储在全局变量environ ,并且是指向环境字符串的以null结尾的指针数组的开头。

ARG_MAX是新进程的最大参数长度

如果您尝试调用具有太多参数的程序,您将看到此错误消息,即最有可能与模式匹配相关:

 $ command * 

它只是exec()系统调用及其直接变体,这将产生此错误。 它们返回相应的错误条件E2BIG()。

shell不应该受到责备,它只是向您提供此错误。 实际上,shell扩展不是问题,因为这里不需要exec()。 扩展仅受虚拟内存系统资源的限制。

因此,以下命令可以顺利运行,因为它们不是将过多的参数移交给新进程,而是仅使用shell内置(echo)或使用控制结构(for循环)迭代参数:

 /dir-with-many-files$ echo * | wc -c /dir-with-many-files$ for i in * ; do grep ARG_MAX "$i"; done 

有不同的方法来学习上限

命令: getconf ARG_MAX

系统调用: sysconf(_SC_ARG_MAX)

系统头:例如<[sys /] limits.h>中的ARG_MAX

与头文件不同, sysconfgetconf告诉实际生效的限制。 这与允许在运行时,通过重新配置,重新编译(例如Linux)或应用补丁(HP-UX 10)来更改它的系统相关。

sysconf()示例用法:

 #include  #include  int main() { return printf("ARG_MAX: %ld\n", sysconf(_SC_ARG_MAX)); } 

如果安装了cpp,可以方便地在标头中找到限制:

 cpp < #include  #include  #include  #include  #include  arg_max: ARG_MAX ncargs: NCARGS EOF 

在查看ARG_MAX / NCARGS ,您必须考虑argv[]envp[] (参数和环境)的空间envp[] 。 因此,您必须至少通过env|wc -cenv|wc -l * 4的结果来减少ARG_MAX,以便对当前可用空间进行良好估计。

POSIX建议另外减去2048,以便该过程可以节省地修改其环境。 使用getconf命令快速估算:

  expr `getconf ARG_MAX` - `env|wc -c` - `env|wc -l` \* 4 - 2048 

获得当前可用空间的最可靠方法是测试exec()的成功与增加的参数长度,直到失败。 这可能很昂贵,但至少你需要检查一次,自动考虑envp []的长度,结果是可靠的。

或者,可以使用GNU autoconf检查 “检查命令行参数的最大长度……”。 它非常相似。

但是,由于意图和简单原因,它会导致更低的值(它可能只是实际值的四分之一):

在增加n的循环中,检查尝试使用参数长度为2n的exec()(但不会检查n高于16,即512kB)。 如果ARG_MAX是2的幂,则最大值为ARG_MAX / 2.最后,找到的值除以2(为安全起见),原因是“C ++编译器可以处理大量额外的参数”。

实际价值

在Linux 2.6.23上,它是堆栈大小的1/4。 内核代码供参考。

我可能错了,但我认为argc和argv属于libc.so.6中的 __libc_start_main
谁叫主?

可能会有所帮助:)

main()在接受的内容方面并不特别。 特别之处在于第一次调用main()之前发生的魔法。

您可以随意调用main()

 #include  char longstring[1024000] = "foo"; int main(int argc, char **argv) { char *p = longstring; printf("main called with argc == %d", argc); if (argv) printf(" and a relevant argv"); puts(""); switch (argc) { case 1: main(2, NULL); break; case 2: main(3, &p); break; default: puts("Uff!"); break; } return 0; }