为什么C标准中没有"recalloc"?

Mat*_*att 11 c malloc allocation realloc calloc

每个人都知道:

  • realloc 调整现有内存块的大小或将其复制到更大的块.
  • calloc 确保内存归零并防止算术溢出,并且通常面向大型阵列.

为什么C标准没有提供如下结合上述两者的功能?

void *recalloc(void *ptr, size_t num, size_t size);
Run Code Online (Sandbox Code Playgroud)

调整大型哈希表或自定义内存池的大小不是很有用吗?

abe*_*nky 15

通常在C中,标准库的要点不是提供丰富的酷函数.它是提供一组必不可少的构建块,您可以从中构建自己的酷功能.

你的提议recalloc很容易写,因此不是标准的lib应该提供的.

其他语言采用不同的方法:C#和Java具有超级丰富的库,甚至使复杂的任务变得微不足道.但它们带来了巨大的开销.C具有最小的开销,并且有助于使其可移植到各种嵌入式设备.

  • @abelenky他所得到的是一些操作系统从不同的池中获取`calloc`页面而不是`malloc`页面(如果可能的话)和calloc使用延迟分配和来自全零的页面的写入时复制.这就是为什么Linux上的`calloc`比`malloc`更快(比`malloc`跟着`memset`快得多). (6认同)
  • @abelenky:你必须经历整个块的其余部分,而不是依赖于预先归零的写时复制内存. (3认同)
  • @abelenky我不会说建议的“recalloc”版本编写起来很简单,即使使用“memset”:为了使“recalloc”作为零扩展副本工作,您必须跟踪内存的初始大小。恕我直言,“realloc”背后的基本原理是让用户不必跟踪分配的内存大小。如果标准库只是提供基本功能,那么它首先就不会引入“realloc”,因为它可以很容易地用条件 malloc-copy-free 语句来表达。 (3认同)
  • 您必须了解系统的虚拟内存,才能有效地编写这样的函数,而无需调用`memset`. (2认同)
  • @MattMcNabb:既没有`size_t`,也没有其他许多人使用的东西. (2认同)

Cor*_*lks 6

我假设你只关注数组的新部分:

并非每个内存分配器都知道您在数组中使用了多少内存.例如,如果我这样做:

char* foo = malloc(1);
Run Code Online (Sandbox Code Playgroud)

foo现在指向至少一块1字节大的内存.但是大多数分配器将分配超过1个字节(例如,8,以保持对齐).

其他分配也可能发生这种情况.内存分配器将至少分配您请求的内存,但通常只需要多一点.

这就是"只是一点点"的一部分,可以解决问题(除了使其变得困难的其他因素).因为我们不知道它是否有用.如果它只是填充,而你,recalloc它,并且分配器不会将它归零,那么你现在拥有一些非零的"新"内存.

例如,如果我recalloc foo让它指向一个至少2个字节大的新缓冲区怎么办?这个额外的字节是否会被清零?或不?它应该是,但请注意,原始分配给了我们8个字节,因此重新分配不会分配任何新内存.就分配器而言,它不需要将任何内存归零(因为没有"新"内存为零).这可能会导致我们的代码中出现严重错误.

  • @Matt:你可以这样做,但现在你把自己画成一个奇怪的角落,这个`recalloc`函数的用处正在减少.您可以通过添加越来越多的任意限制来使其工作,但在某些时候(早晚而不是),更容易要求用户跟踪内存并在"realloc"之后将新内存清零. (2认同)
  • @Matt我的建议 - 更清楚 - 是100001的calloc重新分配,然后是100008,然后回到100001,然后再重复一遍.真正的块大小永远不会改变.但我确实看到,在减少时,填充字节可能为零 - 因此无需保留先前的请求大小.感谢您的挑战. (2认同)
  • @Cornstalks就标准而言,没有额外的字节。分配额外的字节来“保持对齐”是特定实现可能会做的事情,就像它可能会跟踪请求的内存和已发布的内存一样。正如我所说,“recalloc”将强制实现清除那些额外的字节,当然。正如某些架构上的对齐要求迫使实现首先分配这些额外的字节一样。 (2认同)