为什么没有"?;“重新分配”;在C标准中?

为什么没有"?;“重新分配”;在C标准中?,c,malloc,allocation,realloc,calloc,C,Malloc,Allocation,Realloc,Calloc,大家都知道: realloc调整现有内存块的大小或将其复制到更大的块 calloc确保内存清零,防止算术溢出,并且通常面向大型阵列 为什么C标准不提供一个结合了以上两种功能的如下函数 void *recalloc(void *ptr, size_t num, size_t size); 它对调整大型哈希表或自定义内存池的大小不是很有用吗?我假设您只想将数组的新部分归零: 并非每个内存分配器都知道您在一个数组中使用了多少内存。例如,如果我这样做: char* foo = malloc(1);

大家都知道:

  • realloc
    调整现有内存块的大小或将其复制到更大的块
  • calloc
    确保内存清零,防止算术溢出,并且通常面向大型阵列
为什么C标准不提供一个结合了以上两种功能的如下函数

void *recalloc(void *ptr, size_t num, size_t size);

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

我假设您只想将数组的新部分归零:

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

char* foo = malloc(1);
foo
现在指向至少1字节大的内存块。但大多数分配器将分配远远超过1个字节(例如,8,以保持对齐)

其他分配也可能发生这种情况。内存分配器将分配至少与您请求的内存一样多的内存,尽管通常只是多一点

正是这个“稍微多一点”的部分把事情搞砸了(还有其他因素使事情变得困难)。因为我们不知道它是否是有用的记忆。如果它只是填充,而您
recalloc
它,并且分配器没有将其归零,那么您现在拥有了一些非零的“新”内存


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

通常在C语言中,标准库的重点是而不是提供丰富的酷函数集。它提供了一组基本的构建块,您可以从中构建自己的酷功能

您对
recalloc
的建议编写起来很简单,因此不是标准库应该提供的内容


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

如果您只是将所有内容归零,那么调整大小就没有什么意义-只需释放旧块,然后调用一个新块。@PaulR:可能它只会将新内存归零(或者更确切地说,确保它已归零).标准库的目的不是提供一组丰富的酷功能。它提供了一组基本的构建块,您可以从中构建自己的酷功能。你关于recalloc的建议写起来很简单,因此,它不是标准库应该提供的。对我来说,这似乎是一个足够公平的建议,所有考虑的
calloc()
都有另一个
malloc()的特性
没有:在像DOS这样的神秘系统中:分配大于
SIZE\u MAX
的数组的能力。因此,即使
size\u t
为16位,代码也可以
calloc(60000u,sizeof(double))
。我一直想知道这是否符合C标准,但它似乎是正确的。你必须了解系统的虚拟内存,才能高效地编写这样一个函数,而不必调用
memset
@abelenky。他的意思是,一些操作系统从不同于
malloc
的池中获取
calloc
页面页面(如果可能的话)和calloc使用惰性分配,从一个全零的页面进行写时复制。这就是为什么Linux上的
calloc
可以比
malloc
快(并且比
malloc
后面紧跟
memset
的速度快得多)。@abelenky:你必须遍历整个块的其余部分,而不是依赖于写内存上的预调零拷贝。@MattMcNabb:两者都没有
size\u t
,还有许多其他大家都使用的东西。@abelenky我不会说建议的
recalloc
版本编写起来很简单,即使使用
memset
:要使
recalloc
作为零扩展拷贝工作,您必须跟踪内存的初始大小。依我看,
realloc
背后的基本原理是让用户不用跟踪分配内存的大小。如果标准库只是提供基本功能,它从一开始就不会引入
realloc
,因为它可以很容易地用条件malloc-copy-free语句表示。这就是为什么这样一个函数只对大内存块有用的原因。@cornstales:那么必须要注意的是,它只对以前由
calloc
或它本身。@Matt:你可以这么做,但现在你把自己画进了一个奇怪的角落,这个
recalloc
函数的用处正在减少。您可以通过添加越来越多的任意限制来实现这一点,但在某个时候(早一点,而不是晚一点),在
realloc
@Matt之后,要求用户跟踪内存并将新内存归零就更容易了。我的建议——更清楚地说——是calloc重新分配100001,然后是100008,然后回到100001,然后重复。真正的块大小从未改变。但我确实看到,在减少时,填充的字节可能为零,因此不需要保持以前的请求大小。感谢您的挑战。@cornstales就标准而言,没有额外的字节。分配额外的字节来“保持对齐”是特定实现可能做的事情,就像它可能跟踪请求的内存与发出的内存一样。正如我所说,
recalloc
将强制实现清除这些额外的字节,当然。和我一样