【问题标题】:Two arguments to calloccalloc 的两个参数
【发布时间】:2010-11-03 03:02:38
【问题描述】:

为什么calloc 接受两个参数而不是像malloc 这样的一个参数?

具体来说,因为以下表达式之间(或是否存在?)之间没有区别:

calloc (a, b);
calloc (b, a);
calloc (a * b, 1);
calloc (1, a * b);

为什么不直接接受要分配的字节总数?这个界面背后的基本原理是什么?为什么这不适用于 malloc?

【问题讨论】:

标签: c calloc


【解决方案1】:

我听到了两个[互斥的]解释为什么它有两个论点:

  1. calloc 负责检查乘法溢出。如果请求块的总大小太大(如溢出size_t),calloc 返回空指针以指示失败。使用malloc,您必须自己注意溢出,许多人只是忘记这样做。 (尽管标准库的历史知道 calloc 实现忽略溢出的例子,因此工作不正确)。

  2. calloc 实际上允许分配比size_t 类型范围更大的内存块,即calloc 可能能够对其参数执行适当的非溢出大乘法并分配块的结果大小。由于这个原因,由于calloc 使用了两个size_t 类型的参数,它可以分配比malloc 更大的块(因为malloc 只接受一个size_t 类型的参数)。

我一直相信第一个解释是正确的。但是,在阅读了一些关于 SO 的帖子后,我有疑问。

【讨论】:

  • -1,从技术上讲,您不能在size_t 中分配更多相等和大约大于最大值的值,因为它是系统边界,在其他方面这没有任何意义。在 32 位机器上,您将尝试分配所有可能的地址空间,这是不可能的,在 64 位机器上这也会失败。
  • (1) 作为一个理由,对我来说当然听起来更合理。 (2)可能是标准的(也许是意外的)结果。能够通过 calloc 分配 int[SIZE_MAX] 是否有意义,即使您当然不能将其声明为结构的成员(因为 sizeof 无法测量它)?
  • @Svisstack:这正是我在标准中看到的,我认为 AndreyT 提出了一个有趣的观点。 size_t 定义为sizeof 返回的类型。 不是实际上是一个对象的最大尺寸。有些对象不能应用sizeof,特别是动态分配的数组。我认为标准中没有出现“系统边界”一词。如果您想证明(2)中描述的设置实际上是标准禁止的,我认为您必须比“它在我的 64 位系统上失败”做得更好。
  • @Svisstack:我说的是 C 标准。当谈到标准和标准的特定实现之间的区别时,我真的知道我在说什么。这根本不是关于我“想要”如何实现calloc - 如果 AndreT 提出的奇怪事情被标准禁止,我更喜欢它。我只是不明白它在哪里。如果您所说的只是 AndreyT 的选项 (2) 不适用于您的 PC,那么做得好,您是对的。但问题显然是关于 C 标准的基本原理,而不是关于你的 PC。
  • @Svisstack C 标准从来没有说过它只能用于标准机器,有人可以很好地为他们的超级计算机中心编写一个 C 编译器,其中非常大的内存分配实际上是有意义的。跨度>
【解决方案2】:

我相信 malloc 可以保证返回一个根据与第二个参数指示的大小兼容的最粗略要求对齐的内存区域。例如,如果系统要求对齐 2 字节和 4 字节整数,并且第二个参数是 10,则返回的指针必须对齐在 2 字节边界上;如果第二个参数是 12,则指针将在四字节边界上对齐。我怀疑实际上许多系统会将所有返回的指针对齐到可能需要的最大边界,无论大小如何,但我认为除了 calloc 之外不需要它。

【讨论】:

    【解决方案3】:

    唯一显着的区别是calloc 需要将分配的空间初始化为零,而malloc 没有这样的保证。否则,我猜只是出于历史原因,有两个不同的功能。

    【讨论】:

    • 除了calloc 可能比malloc 后跟memset 快。
    【解决方案4】:

    Everything is just bytes 是一项相对较新(即 c/Unix 时代)的发明——在许多其他架构上,都是固定大小的记录。

    【讨论】:

      【解决方案5】:

      calloc(x,y) 等价于malloc(x*y)

      但是calloc 正在做额外的事情(使用memset(block, 0, x*y) 将值设置为0)

      这个函数只是为了漂亮地传递元素的大小元素的数量,在malloc中你必须乘以这个值来获得所需的字节数,这个函数在乘法中也检查整数溢出。

      例如,如果你想为 12 个整数分配内存并且你想对这些整数做一些事情,并且你必须将她的值设置为 0,请使用 calloc(12, sizeof(int))

      但是,如果您想分配一些内存块(256 字节)以在将来复制一些字符串,那么memset 对您不可用,那么更好的使用是malloc(sizeof(char) * 256) 或例如malloc(sizeof(wchar_t) * 256)


      void *
      calloc (size_t nmemb, size_t lsize)
      {
        void *ptr;
        struct __meminfo *info;
        size_t size = lsize * nmemb;
      
        /* if size overflow occurs, then set errno to ENOMEM and return NULL */
        if (nmemb && lsize != (size / nmemb))
          {
            set_errno (ENOMEM);
            return NULL;
          }
      
        /* allocate memory */
        ptr = malloc (size);
      
        /* get pointer to info part of chunk */
        info = __mem2info (ptr);
      
        /* fill memory with zeros and set __MEM_CALLOC flag */
        memset (ptr, 0, info->size);
        info->flags |= __MEM_CALLOC;
      
        return ptr;                   /* happy end */
      }
      

      【讨论】:

      • 小毛病:sizeof(char) 根据定义为 1。
      • 小心乘法的整数溢出。
      • 这个函数只是为了很好地传递元素的大小和元素的数量,在 malloc 中你必须乘以这个值来获得所需的字节数。 -> 所以为什么我们没有与malloc 类似的界面?
      • @theDigitalEngel:这不是一个简单的界面,当您必须将所有值归零时,此函数是用于声明某些向量数组的快捷方式。在其他时候,为什么不呢?
      • 有趣的是calloc的接口(我说的是向量数组部分,不是内存归零部分)甚至不是快捷方式; calloc (a, b)calloc (a * b) 的字符数相同。事实上,在第一种情况下,只分配一个元素 (calloc (a, 1)) 是不必要的复杂。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-14
      • 1970-01-01
      • 1970-01-01
      • 2023-03-02
      • 2014-05-28
      • 2010-10-12
      相关资源
      最近更新 更多