【问题标题】:C argv what is the maximum size of data [duplicate]C argv 数据的最大大小是多少[重复]
【发布时间】:2013-01-03 09:01:14
【问题描述】:

可能重复:
About command line arguments of main function

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

【问题讨论】:

  • 它可能因您运行程序的系统而有很大不同。查看我的回复以供参考以及如何找到系统中的限制
  • 关于重复,重复的链接标题不包含足够具体的信息,无法找到。但是,接受的答案也回答了这个问题。

标签: c argv


【解决方案1】:

在 POSIX 系统中,ARG_MAX 中定义了一个值 <limits.h> ,其可接受的最小值为 _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中的值相同,并且是指向环境字符串的以 null 结尾的指针数组的开始。

【讨论】:

    【解决方案2】:

    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 在例如

    与标题相反,sysconfgetconf 告诉实际有效的限制。 这与允许在运行时通过重新配置更改它的系统相关, 通过重新编译(例如 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[](参数和环境)的空间消耗。 因此,您必须至少将 ARG_MAX 减少 env|wc -cenv|wc -l * 4 的结果,以便更好地估计当前可用空间。

    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供参考。

    【讨论】:

      【解决方案3】:

      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;
      }
      

      【讨论】:

      • 你可以在 C 中做到这一点;你不能在 C++ 中做到这一点(并且问题被标记为 C,所以你的答案是好的)。当系统调用main()时,有argc &gt;= 1argv[argc] == 0等保证;当你调用它时,你可以强加任何你喜欢的规则,所以你的case 1调用是可以的,因为你做了,但如果系统尝试它就不行了。
      • 这就是我所说的“在第一次调用main() 之前发生的特殊魔法”。
      【解决方案4】:

      我可能错了,但我认为 argc 和 argv 属于 libc.so.6
      Who calls main ? 中的 __libc_start_main

      可能会有所帮助:)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-01-09
        • 2011-03-16
        • 1970-01-01
        • 2010-12-15
        • 1970-01-01
        • 2017-01-28
        • 2019-08-18
        • 1970-01-01
        相关资源
        最近更新 更多