我如何确定可以传递到C main的最大数据大小(int argc,char * argv)?标准中是否有一个宏来定义它?数据是否由主进程“拥有”(即我的程序是否存储了这些数据),还是由操作系统以某种方式“拥有”,我可以获得指向它的指针?
答案 0 :(得分:7)
在POSIX系统中,<limits.h>
中定义了一个值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)
(在C标准附件J,§J.5.1中被认为是扩展),其中envp
与存储在全局变量中的值相同environ
,并且是以空字符结尾的指向环境字符串的指针数组的开始。
答案 1 :(得分:5)
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)
系统标题:例如,ARG_MAX百分比抑制率数据SYS /] limits.h中&GT;
与标题相比,sysconf
和getconf
告诉实际生效的限制。
这与允许在运行时通过重新配置更改它的系统相关
通过重新编译(例如Linux)或应用补丁(HP-UX 10)。
sysconf()
的使用示例:
#include <stdio.h>
#include <unistd.h>
int main() {
return printf("ARG_MAX: %ld\n", sysconf(_SC_ARG_MAX));
}
如果您安装了cpp,则可以方便地在标头中找到限制:
cpp <<EOF
#include <limits.h>
#include <param.h>
#include <params.h>
#include <sys/limits.h>
#include <sys/param.h>
#include <sys/params.h>
arg_max: ARG_MAX
ncargs: NCARGS
EOF
查看ARG_MAX
/ NCARGS
时,您必须考虑argv[]
和envp[]
(参数和环境)的空间消耗。
因此,您必须至少通过env|wc -c
和env|wc -l * 4
的结果来降低ARG_MAX,以便对当前可用空间进行良好估算。
POSIX建议另外减去2048,以便该过程可以节省地修改其环境。使用getconf命令快速估算:
expr `getconf ARG_MAX` - `env|wc -c` - `env|wc -l` \* 4 - 2048
获取当前可用空间的最可靠方法是测试exec()的成功与增加的参数长度,直到失败。 这可能很昂贵,但至少你需要检查一次,自动考虑envp []的长度,结果是可靠的。
或者,可以使用GNU autoconf check“检查命令行参数的最大长度......”。它非常相似。
然而,由于意图和简单原因,它导致价值低得多(它只能是实际价值的四分之一):
在增加n的循环中,检查尝试使用参数长度为2n的exec()(但不会检查n高于16,即512kB)。 如果ARG_MAX是2的幂,则最大值为ARG_MAX / 2。 最后,找到的值除以2(为安全起见),原因是“C ++编译器可以解决大量额外的参数”。
实际值
在Linux 2.6.23上,它是堆栈大小的1/4。 Kernel code供参考。
答案 2 :(得分:0)
我可能错了,但我认为argc和argv属于 libc.so.6 中的 __ libc_start_main Who calls main ?
可能会有帮助:)
答案 3 :(得分:0)
main()
对于它所接受的内容并不特别。特别之处在于第一次调用main()
之前发生的魔法。
您可以随心所欲地致电main()
......
#include <stdio.h>
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;
}