可能重复:
关于主函数的命令行参数
我将如何确定可以传递给 C main(int argc, char* argv) 的最大数据大小?标准中是否有一个宏可以定义这个?数据是由主进程“拥有”的(即我的程序是否存储这些数据),还是它以某种方式被操作系统“拥有”,我可以得到一个指向它的指针?
可能重复:
关于主函数的命令行参数
我将如何确定可以传递给 C main(int argc, char* argv) 的最大数据大小?标准中是否有一个宏可以定义这个?数据是由主进程“拥有”的(即我的程序是否存储这些数据),还是它以某种方式被操作系统“拥有”,我可以得到一个指向它的指针?
在 POSIX 系统中,有一个值 ,ARG_MAX
定义<limits.h>
为最小可接受值_POSIX_ARG_MAX
(即 4096)。sysconf()
您可以通过带有参数的函数在运行时发现该值SC_ARG_MAX
。
它通常是 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
,并且是以空值结尾的开始指向环境字符串的指针数组。
ARG_MAX
是新进程的最大参数长度
如果您尝试调用具有太多参数的程序,即很可能与模式匹配有关,您将看到此错误消息:
$ command *
只有exec()
系统调用及其直接变体会产生此错误。它们返回相应的错误条件 E2BIG()。
不应责怪外壳,它只是将这个错误传递给您。事实上,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
与标题对比,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[]
and 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 检查“正在检查命令行参数的最大长度...”。它的工作原理非常相似。
但是,出于意图和简单的原因,它导致的值要低得多(它可能只是实际值的四分之一):
在 n 增加的循环中,检查尝试使用参数长度为 2n 的 exec()(但不会检查 n 是否大于 16,即 512kB)。如果 ARG_MAX 是 2 的幂,则最大值为 ARG_MAX/2。最后,找到的值除以 2(为了安全),原因是“C++ 编译器可以处理大量附加参数”。
实际值
在 Linux 2.6.23 上,它是堆栈大小的 1/4。内核代码供参考。
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;
}
我可能错了,但我认为 argc 和 argv 属于libc.so.6中的__libc_start_main谁调用 main ?
可能会有所帮助:)