【发布时间】:2019-04-09 13:33:21
【问题描述】:
阅读realloc() 的手册页后,我意识到它的工作方式与我想象的有点不同。我最初认为realloc() 会尝试调整缓冲区的大小,该缓冲区以前分配有 malloc 系列函数之一,如果它不能就地扩展缓冲区,那么它将失败。但是,手册页指出:
realloc() 函数返回一个指向新分配内存的指针,该指针适合任何内置类型对齐,并且可能与 ptr 不同,如果请求失败,则为 NULL。
“可能与 ptr 不同”部分就是我所说的。
基本上,我想要的是一个类似于realloc() 的函数,但如果它不能就地扩展缓冲区,它就会失败。似乎标准 C 库中没有执行此操作的函数;但是,我假设可能有一些特定于操作系统的功能可以完成同样的事情。
谁能告诉我有哪些功能可以执行我上面描述的操作,以及它们特定于哪些操作系统?最好,我至少想知道特定于 Linux 和 Windows 的功能(Mac OS 也会是一个不错的奖励:))。
这可能是this post的重复,但我认为不是因为以下原因:
我链接到的帖子中的问题只是问,是否有一个扩展缓冲区的函数,而我问的是,哪个函数就地扩展缓冲区。
该帖子接受的答案不包含我需要的信息。
编辑
有些人想知道我需要这个的用例是什么,所以我将在下面解释:
我正在编写一个 C 预处理器(是的,我知道......不要重新发明轮子......好吧,无论如何我都在做,所以在那里)。 C 预处理器的一个组件是用于存储来自各种源文件的 pp-tokens 的缓存,其中每个源文件的 pp-tokens 集可能在缓存中分段。缓存本身是大块内存的链表。理想情况下,我想保持这个链表简短,因此我想首先尝试调整缓冲区的大小(就地);但是,如果无法就地调整大小,那么我只想将另一个节点(即内存块)添加到链表中。
在每个缓存缓冲区中,还有额外的链表节点,它们提供了一种迭代每个单独源文件的所有 pp-tokens 的方法,这些文件可能在组成缓存的各种缓存缓冲区中分段。
我需要我之前讨论的那种内存重新分配的原因如下:
如果无法就地调整缓存缓冲区的大小,并且必须分配新缓冲区并复制旧的内存内容,那么我会有很多悬空指针。 Jonathan Leffler 建议我将偏移量存储在缓冲区中,而不是指针,我什至没有考虑过,这是一个好主意!但是,原因 #2...
我希望缓存的实现尽可能快,并且,如果我错了,请纠正我,但在我看来(对于我的用例)平均而言它会更快如果给定的缓存缓冲区无法就地调整大小,只需向链表添加一个新的缓存缓冲区,而不是分配一个新的缓冲区并复制所有以前的内容并释放旧的缓冲区。作为旁注,我计划在每次需要调整缓存大小时将分配的缓存缓冲区的大小加倍。
【问题讨论】:
-
C 没有这样的功能。你为什么要关心
realloc是否分配了一个足够大小的单独内存块并将现有数据复制到它,释放原始数据并在成功时返回指向新块的指针,否则NULL。你能解释一下为什么你认为你需要扩展同一个块吗?您可以查看mmap,但我不确定这是否能保证相同的块。 (我认为您很困惑——就地扩展缓冲区并为该扩展缓冲区分配存储空间?) -
只是好奇,你为什么需要那个?很可能您正在寻找不存在的问题的解决方案..
-
我在任何类 Unix 平台上都没有听说过这样的功能,但它可能存在或被创建。如果问题是您在分配的空间中存储的指针在移动分配时会中断,那么主要的答案是“不要那样做——使用偏移量而不是指针”。也就是说,不是指针,而是存储从块开始的偏移量。然后,当您需要访问它时,获取块的当前起始地址并添加适当的偏移量以获取数据。即使
realloc()移动数据改变了基地址,这也能正常工作(小心)。 -
因为 malloc 主要使用 sbrk(),如果需要更多内存,它会增加堆指针,所以下一个 malloc 将在前一个之上传递一个块,所以前一个不能在同一个地方生长。
-
@holger:这不是当今常见的 malloc 实施策略。您可能会在一些最小的嵌入式系统中找到它,但它肯定不是 malloc 在常见桌面操作系统上的工作方式。