代码之家  ›  专栏  ›  技术社区  ›  Toby Speight

calloc()总共能分配超过SIZE\u MAX吗?

  •  29
  • Toby Speight  · 技术社区  · 7 年前

    a recent code review

    在选定系统上, calloc() 可以分配超过 SIZE_MAX 总字节数 malloc()

    我认为那是错的,因为 calloc() 最大尺寸 .

    size_t ,是 最大尺寸

    更具体地说:以下程序是否会以非零状态退出?

    #include <stdint.h>
    #include <stdlib.h>
    
    int main()
    {
         return calloc(SIZE_MAX, 2) != NULL;
    }
    
    7 回复  |  直到 7 年前
        1
  •  18
  •   Lundin    7 年前

    SIZE_MAX 不需要指定对象的最大大小,而是指定对象的最大值 size_t ,这不一定是一回事。看到了吗 Why is the maximum size of an array "too large"?

    最大尺寸 对一个期望 参数。所以在理论上 calloc SIZE_MAX * SIZE_MAX 要分配的字节数。

    那件事 malloc 它们分配的对象没有类型。具有类型的对象有一些限制,例如从不大于某个限制,例如 最大尺寸

    声明的类型 有效类型 用于存储的数据访问(C17 6.5§6).

    分配 分配比C中任何类型都能容纳的内存更多的内存,因为分配的内存没有类型。

    因此,就C标准而言,它对于 calloc(SIZE_MAX, 2)

        2
  •  20
  •   chux    7 年前

    calloc()总共能分配超过SIZE\u MAX吗?

    正如“在选定的系统上, calloc() 可以分配超过 SIZE_MAX 总字节数 malloc() comment 我发帖了,我会解释我的理由。


    大小\u t

    size_t 未签名

    大小\u t sizeof 操作员;C11dr型§七点一九二

    “其执行定义值的大小应等于或大于 ... 比下面给出的相应值“。。。限制 ... 65535§7.20.3 2

    这个 运算符生成其操作数的大小(以字节为单位),该操作数可以是

    分配

    void *calloc(size_t nmemb, size_t size);
    

    这个 calloc nmemb size


    nmemb * size 最大尺寸 .

    size_t alot = SIZE_MAX/2;
    double *p = calloc(alot, sizeof *p); // assume `double` is 8 bytes.
    

    calloc() 真正分配的 nmemb*大小 p != NULL 是真的, 这违反了什么规范?

    // Nicely reports the size of a pointer and an element.
    printf("sizeof p:%zu, sizeof *p:%zu\n", sizeof p, sizeof *p); 
    

    每个元素都可以访问。

    // Nicely reports the value of an `element` and the address of the element
    for (size_t i = 0; i<alot; i++) {
      printf("value a[%zu]:%g, address:%p\n", i, p[i], (void*) &p[i]); 
    }
    

    calloc()

    “数组的空间” “对象”:这当然是争论的一个关键点。“为数组分配空间”是否需要<= 最大尺寸

    calloc() 可以分配超过


    当然是 不寻常的 calloc() 使用大参数返回非- NULL -是否合规。通常这样的分配会超过可用内存,所以这个问题没有意义。我遇到的唯一一个案例是 Huge memory model 大小\u t 为16位,对象指针为32位。

        3
  •  2
  •   Community Mohan Dere    5 年前

    7.22.3.2 calloc函数

    简介

     #include <stdlib.h>
     void *calloc(size_t nmemb, size_t size);`
    

    说明
    2 calloc函数为nmemb对象数组分配空间,每个对象的大小都是size。空间初始化为所有位零。

    退换商品
    3 calloc函数返回空指针或指向分配空间的指针。

    SIZE_MAX 字节。

        4
  •  2
  •   Florian Weimer    7 年前

    如果程序超出了实现限制,则行为是未定义的。这源于实现限制的定义

    该标准也没有定义可能存在的实现限制,因此这有点 全权委托 ,但我认为最大对象大小实际上与对象分配相关是合理的(最大对象大小通常为 SIZE_MAX ,顺便说一下,因为指向- char 内的对象必须在中表示 ptrdiff_t

    这使我们得出以下结论:呼吁 calloc (SIZE_MAX, 2) 超过最大对象大小限制,因此实现可以返回任意值,同时仍符合标准。

    一些实现实际上会返回一个指针,对于类似 calloc (SIZE_MAX / 2 + 2, 2) 因为实现不会检查乘法结果是否与 size_t calloc 一个实现bug,当我看到它们时,我已经向实现者报告了bug,但从技术上讲,这仅仅是一个实现质量问题。

    对于堆栈上的可变长度数组,关于超出实现限制导致未定义行为的规则更为明显:

    size_t length = SIZE_MAX / 2 + 2;
    short object[length];
    

        5
  •  2
  •   Toby Speight    7 年前

    根据标准的文本,可能是因为标准(有些人会故意说)对这类事情含糊不清。

    这个 sizeof 运算符产生其操作数的大小(以字节为单位)

    根据7.19.2:

    它是

    如果实现允许任何类型(包括数组类型),而这些类型的大小不能用 size_t calloc 指向“数组”,总是有一个数组涉及到任何对象:类型的重叠数组 unsigned char[sizeof object] 哪个是它的 代表

    充其量是允许创建任何大于 SIZE_MAX (或 PTRDIFF_MAX

        6
  •  2
  •   gnasher729    7 年前

    只是一个补充:通过一点点的数学运算,你可以显示SIZE\u MAX*SIZE\u MAX=1(当根据C规则计算时)。

    但是,calloc(SIZE\u MAX,SIZE\u MAX)只允许执行以下两项操作之一:返回指向SIZE\u MAX字节的SIZE\u MAX元素数组的指针,或者返回NULL。不允许仅通过将参数相乘,得到结果1,然后分配一个字节(清除为0)来计算总大小。

        7
  •  0
  •   supercat    7 年前

    ptr+number1+number2 可能是有效的指针,但是 number1+number2 将超过 SIZE_MAX 数字1+数字2 超过 PTRDIFF_MAX ptrdiff_t

    该标准并不要求实现提供任何方法来创建指向此类大型对象的指针。但它确实定义了一个函数, calloc() 如果无法创建对象,则应返回空指针。

    然而,有效地分配任何类型对象的能力是实现的质量问题。该标准不会要求任何特定的分配请求成功,也不会禁止实现返回可能无法使用的指针(在某些Linux环境中,malloc()可能会产生指向地址空间的过度提交区域的指针;物理存储不足时尝试使用指针可能会导致致命的陷阱)。当然,不反复无常地实施这项计划会更好 calloc(x,y) x y 超过大小\u MAX,它将产生一个指针,该指针不能用于访问该字节数。但是,无论是否返回可用于访问的指针,标准都是静默的 null . 每种行为在某些情况下都是有利的,而在另一些情况下则是不利的。