为什么C中的`free`不占用要释放的字节数?


84

明确一点:我确实知道mallocfree在C库中实现,该库通常从OS分配内存块,并进行自己的管理以将较小的内存分配给应用程序,并跟踪分配的字节数。这个问题不是免费如何知道多少免费

相反,我想知道为什么free首先要采用这种方式。作为一种低级语言,我认为要求C程序员不仅跟踪分配了什么内存而且跟踪多少内存是完全合理的(实际上,我通常发现我最终跟踪了字节数)仍然分配)。在我看来,明确给出字节数free可能会允许某些性能优化,例如,具有针对不同分配大小的单独池的分配器将能够通过查看输入参数来确定要释放哪个池,并且总体而言,空间开销会更少。

因此,简而言之,为什么要创建mallocfree创建它们以使它们在内部跟踪分配的字节数?这只是历史性的意外吗?

一个小的修改:一些人提供了一些要点,例如“如果您释放的金额与分配的金额不同,将会怎样?” 我想象中的API可能只需要一个就可以准确释放分配的字节数。释放或多或少可以简单地由UB或实现定义。不过,我不想阻止关于其他可能性的讨论。


18
因为一直跟踪分配本身已经很麻烦,而且如果您还必须跟踪大小,它甚至会使代码更加复杂。
延斯·古斯特

11
我可以想到以下几个原因:为何使用户不必这样做?如果用户搞砸了怎么办?无论如何,这是一个多余的问题。如果他们做出了其他选择,您仍然会问为什么。
BoBTFish 2014年

15
@BoBTFish:我们正在谈论的是C,而不是Python甚至C ++。用户已经必须执行$ h!1吨的操作,而不必这样做。那不是原因。
user541686

4
K&R也无话可说。我们可以推测我们喜欢的一切,但我认为最初的原因可能会在历史上丢失
BoBTFish 2014年

35
您不能要求程序员正确传入块的大小,因为的调用者malloc不知道返回的块的大小malloc通常会返回大于请求的块。充其量,程序员可以传入malloc()调用中请求的大小,这完全对实现者毫无帮助free()
Ben Voigt 2014年

Answers:


97

一个参数free(void *)(在Unix V7中引入)比以前的两个参数具有另一个主要优势mfree(void *, size_t)没有提及的:这里没有提到:一个参数free极大地简化了所有其他与堆内存一起使用的API。例如,如果free需要存储块的大小,则将strdup不得不以某种方式返回两个值(指针+大小)而不是一个值(指针),并且C使多值返回比单值返回更加麻烦。而不是char *strdup(char *)我们不得不写char *strdup(char *, size_t *),否则struct CharPWithSize { char *val; size_t size}; CharPWithSize strdup(char *)。(现在,第二种选择看起来很诱人,因为我们知道以NUL终止的字符串是“计算历史上最灾难性的设计错误”。,但这是事后看来。在70年代,C能够将字符串作为简单的字符串进行处理。char *实际上,它被认为比Pascal和Algol等竞争者具有决定性的优势。)此外,不仅仅是strdup受此问题困扰,它还会影响分配堆内存的每个系统或用户定义的函数。

早期的Unix设计师是非常聪明的人,并且有很多理由说明为什么free要比mfree基本上更好,我认为问题的答案是他们注意到了这一点并据此设计了系统。我怀疑您在做出决定时会发现他们脑海中发生的任何直接记录。但是我们可以想象。

假设您要使用C编写应用程序以在V6 Unix(带有两个参数)上运行mfree。到目前为止,您的工作还不错,但是随着程序的发展,跟踪这些指针的大小变得越来越麻烦变得更加雄心勃勃,并且需要越来越多地使用堆分配的变量。但是,然后您有了一个绝妙的主意:您不必size_t编写所有函数,而只需编写一些实用程序函数即可,这些函数直接将大小存储在分配的内存中:

void *my_alloc(size_t size) {
    void *block = malloc(sizeof(size) + size);
    *(size_t *)block = size;
    return (void *) ((size_t *)block + 1);
}
void my_free(void *block) {
    block = (size_t *)block - 1;
    mfree(block, *(size_t *)block);
}

使用这些新功能编写的代码越多,它们看起来就越强大。他们不仅使你的代码更容易编写,他们让你的代码更快-两件事情不经常一起去!在size_t各处传递这些s之前,这增加了复制的CPU开销,这意味着您不得不更频繁地溢出寄存器(尤其是多余的函数参数),并浪费内存(因为经常会导致嵌套函数调用)以多个副本size_t形式存储在不同的堆栈框架中)。在新系统中,您仍然必须花费内存来存储size_t,但只能复制一次,并且永远不会复制到任何地方。这些效率似乎很小,但请记住,我们所谈论的是具有256 KiB RAM的高端机器。

这让你开心!因此,您与正在开发下一个Unix版本的有胡子的人分享了很酷的技巧,但这并不能使他们感到高兴,而会让他们感到悲伤。您会看到,它们只是在添加一堆新的实用程序功能,例如strdup,他们意识到使用您的绝妙技巧的人们将无法使用其新功能,因为他们的新功能都使用了繁琐的指针+大小API。然后让你伤心过,因为你意识到你必须重写好strdup(char *)自己功能每次你写的程序,而不是能够使用的系统版本。

可是等等!这是1977年,向后兼容不会再发明5年了!此外,没有人真正使用这种晦涩的“ Unix”名称及其变色名称。K&R的第一版现已面世,但这没问题-它在第一页上说:“ C没有提供直接处理诸如字符串之类的复合对象的操作……没有堆。 ...”。在这个历史时刻,string.h并且malloc是供应商扩展(!)。因此,建议有胡子的人#1,我们可以根据需要更改它们;我们为什么不只宣布您棘手的分配器为正式分配器?

几天后,Bearded Man#2看到了新的API并说,嘿,等等,这比以前要好,但是它仍然会为分配大小花费整个单词。他认为这是亵渎的下一件事。其他人都像疯了一样看着他,因为你还能做什么?那天晚上,他待到很晚,发明了一个根本不存储大小的新分配器,而是通过对指针值执行黑魔术位移位来动态推断出它,并在保持新API不变的情况下进行交换。新的API意味着没有人注意到此切换,但是他们确实注意到第二天早上编译器使用的RAM减少了10%。

现在所有人都高兴了:您得到了更易于编写和更快的代码,Bearded Man#1获得了一个strdup可以供人们实际使用的简单方法,而Bearded Man#2获得了一点点保留的自信- -回到弄糟的藜。装运它!

或者至少,这是它可能发生。


14
Err,以防万一,这是一场幻想,带有确定的细节以提供艺术上的真实感。与生死者的任何相似之处纯粹是因为涉及的每个人看上去都一样。请不要混淆实际的历史记录。
纳撒尼尔·史密斯

5
你赢了。在我看来,这似乎是最合理的解释(也是最好的写作)。即使这里的一切都被证明是不正确或无效的,对于留着胡须的人的出色描写,这也是最好的答案。
jaymmer-恢复莫妮卡2014年

哇,这个页面上的答案听起来似乎很合理。向我+1。
541686

更好-此页面上的答案实际上很有趣!+1。
大卫·兰金

我想知道是否有著名的Pascal系统以类似于微型计算机BASIC解释器的方式使用了垃圾收集的字符串池?C的语义不适用于此类事情,但是在Pascal中,如果代码保持可追溯的堆栈框架(许多编译器仍然这样做),则可以很好地处理此类问题。
2015年

31

“为什么free在C中不占用要释放的字节数?”

因为没有必要,而且还是没有任何意义

分配内容时,您想告诉系统要分配多少字节(出于明显的原因)。

但是,当您已经分配了对象时,现在就可以确定返回的存储区域的大小。它是隐式的。这是一个连续的内存块。您不能取消分配其中的一部分(让我们忘记了realloc(),那不是它要做的事情),您只能取消分配整个事情。您也不能“释放X字节”-要么释放获得的内存块,要么不释放malloc()

现在,如果要释放它,则可以告诉内存管理器系统:“这是指针,free()它指向的块。” -并且内存管理器将知道如何执行此操作,这是因为它隐式知道大小,或者因为它甚至可能不需要大小。

例如,最典型的实现是malloc()维护指向空闲和已分配内存块的指针的链接列表。如果将指针传递给free(),它将仅在“已分配”列表中搜索该指针,取消链接相应的节点并将其附加到“空闲”列表。它甚至不需要区域大小。仅当它潜在地试图重用所讨论的块时,才需要该信息。


如果我从您那里借了100美元,然后又从您那里借了100美元,然后又进行了5次,那么您是否真的在乎我是否从您那里借了7次钱(除非您实际上要收取利息!)?还是您只是在乎我是否向您借了700美元?同样的事情:系统只关心未分配的内存,它不关心(也不需要也不应)分配的内存如何分配。
user541686

1
@Mehrdad:不,不是。C,但是。它的全部目的是使事情(稍微)更安全。我真的不知道你在这里找什么。
Lightness Races in Orbit

12
@ user3477950:不需要传递字节数:是的,因为它是通过这种方式设计的。OP问为什么要这样设计?
重复数据删除器2014年

5
“因为它不需要”-它本来可以设计得确实需要。
user253751

5
@Mehrdad,一个完全不清楚和错误的类比。如果您每百次分配4个字节,那么最确切的一点就是释放哪个字节。释放第一个与释放第二个不同。另一方面,用钱也没关系,无论您是先还第一笔还是第二笔借款,这只是
一大笔钱

14

C可能不像C ++那样“抽象”,但是它仍然是对汇编的抽象。为此,将最底层的细节排除在等式之外。在大多数情况下,这避免了您不得不为对齐和填充而烦恼,这会使所有C程序不可移植。

简而言之,这就是编写抽象的全部要点


9
不确定与此相关的对齐方式或填充方式。答案并没有真正回答任何问题。
user541686

1
@Mehrdad C不是x86语言,它(或多或少)尝试具有可移植性,从而使程序员摆脱了巨大的负担。无论如何,您都可以通过其他各种方式(例如,内联汇编)达到该级别,但是抽象是关键。我同意这个答案。
Marco A.

4
@Mehrdad:如果您请求mallocN个字节,而是返回指向整个页面开头的指针(由于对齐,填充或其他限制,则用户无法跟踪它-迫使他们你会适得其反。
迈克尔Foukarakis

3
@MichaelFoukarakis:malloc可以随时返回对齐的指针,而无需存储分配的大小。free然后可以四舍五入到适当的对齐方式,以确保所有内容均正确释放。我看不出问题出在哪里。
user541686

6
@Mehrdad:您刚才提到的所有额外工作都没有好处。另外,传递size参数来free打开另一个错误源。
Michael Foukarakis 2014年

14

实际上,在古老的Unix内核内存分配器中,mfree()发生了size争执。malloc()mfree()保留了两个数组(其中一个用于核心内存,另一个用于交换),其中包含有关空闲块地址和大小的信息。

在Unix V6之前没有用户空间分配器(程序只能使用sbrk())。在Unix V6中,iolib包括一个分配器alloc(size)和一个free()不带size参数的调用。每个内存块之前都有其大小和指向下一个块的指针。在遍历空闲列表时,该指针仅在空闲块上使用,并且在使用中的块上被重新用作块存储器。

在Unix 32V和Unix V7中,这被新的malloc()free()实现所代替,而在此free()没有size参数。该实现是一个循环列表,每个块之前都有一个单词,该单词包含一个指向下一个块的指针以及一个“忙”(已分配)位。因此,malloc()/free()甚至没有跟踪明确的大小。


10

为什么free在C中不占用要释放的字节数?

因为它不需要。该信息已在malloc / free执行的内部管理中可用。

以下是两个注意事项(可能会或可能不会影响此决定):

  • 您为什么会期望函数接收不需要的参数?

    (这实际上会使依赖于动态内存的所有客户端代码复杂化,并为您的应用程序添加完全不必要的冗余)。跟踪指针分配已经是一个难题。跟踪内存分配以及相关的大小会不必要地增加客户端代码的复杂性。

  • free在这种情况下,更改后的功能会做什么?

    void * p = malloc(20);
    free(p, 25); // (1) wrong size provided by client code
    free(NULL, 10); // (2) generic argument mismatch
    

    它会不会释放(导致内存泄漏?)?忽略第二个参数?通过调用exit停止应用程序?实施此操作会在您的应用程序中增加额外的故障点,对于您可能不需要的功能(如果需要,请参阅下面的最后一点-“在应用程序级别实施解决方案”)。

相反,我想知道为什么首先要通过这种方式获得免费。

因为这是“正确”的方法。API应该要求执行其操作所需的参数,并且仅此一个即可

我还发现,显式地指定要释放的字节数可能会进行一些性能优化,例如,具有针对不同分配大小的单独池的分配器将能够通过查看输入参数来确定要释放的池,并且总体上会减少空间开销。

实现该目标的正确方法是:

  • (在系统级别)在malloc的实现中-不会阻止库实现者根据接收到的大小编写malloc以在内部使用各种策略。

  • (在应用程序级别),方法是将malloc和free包装在自己的API中,然后改用它们(可能需要在应用程序中的任何位置)。


6
@ user3477950:不需要传递字节数:是的,因为它是通过这种方式设计的。OP问为什么要这样设计?
重复数据删除器2014年

4
“因为它不需要”-可以通过不保存该信息来设计它,使其确实需要。
user253751

1
关于第二点,我想知道是否定义了free(NULL)行为。啊哈,“所有的标准C库免费治疗(NULL)作为无操作的兼容版本” -源stackoverflow.com/questions/1938735/...
Mawg说恢复莫妮卡

10

想到五个原因:

  1. 很方便 它消除了程序员的全部负担,避免了一类极难跟踪的错误。

  2. 它提供了释放部分块的可能性。但是由于内存管理人员通常希望获得跟踪信息,因此不清楚这意味着什么?

  3. 围绕轨道的“亮度竞赛”是关于填充和对齐的。内存管理的性质意味着分配的实际大小可能与您要求的大小完全不同。这意味着free需要malloc更改大小和位置,还必须返回分配的实际大小。

  4. 尚不清楚传递大小是否有任何实际好处。典型的内存管理器每个内存块都有4-16字节的标头,其中包括大小。对于已分配和未分配的内存,此块头可能是通用的,当相邻块释放时,它们可以折叠在一起。如果让调用者存储空闲内存,则可以通过在分配的内存中没有单独的size字段来释放每个块大约4个字节的空间,但是由于调用者需要将其存储在某个地方,因此无论如何都不会获得该size字段。但是现在,该信息分散在内存中,而不是可预测地位于标头块中,而这在操作上无论如何还是效率较低。

  5. 即使更高效的它根本不太可能您的程序花费了大量的时间释放内存的反正这样的好处是微小的。

顺便说一句,如果没有此信息,关于不同大小项目的单独分配器的想法很容易实现(您可以使用地址来确定分配发生的位置)。这通常是用C ++完成的。

以后添加

另一个答案相当荒谬,它提出了std :: allocator作为free可以以这种方式工作的证明,但实际上,它是为什么free不能以这种方式工作的一个很好的例子。malloc/free行为与std :: allocator行为之间有两个主要区别。首先,malloc而且free面向用户-它们是供一般程序员使用的-std::allocator被设计为标准库提供专业的内存分配。这提供了一个很好的例子,说明我的第一个观点何时无关紧要。由于它是一个库,因此无论如何,对于用户而言,隐藏跟踪大小的复杂性的困难都是隐藏的。

其次,std :: allocator始终与相同大小的项目一起使用,这意味着它有可能使用最初传递的元素数量来确定有多少空闲空间。为什么这与free本身不同是说明性的。在std::allocator要分配的物料中,物料总是相同,已知,大小且始终相同,因此它们始终具有相同的对齐要求。这意味着分配器可以专门用于在开始时简单分配这些项的数组,并根据需要分配它们。您无法执行此free,因为没有办法保证最佳的尺寸是回报的大小要求,取而代之的则是更加高效有时返回较大块不是调用者询问*,因此无论是用户或管理员需要跟踪实际授予的确切大小。将这些实现细节传递给用户是不必要的麻烦,不会给调用者带来任何好处。

-*如果仍然很难理解这一点,请考虑以下问题:典型的内存分配器会向内存块的开头添加少量跟踪信息,然后从此位置返回指针偏移量。例如,此处存储的信息通常包括指向下一个空闲块的指针。假设标头只有4个字节长(实际上比大多数真实库要小),并且不包括大小,那么想象一下,当用户要求16个字节的块时,我们有20个字节的空闲块系统会返回16字节的块,但会留下一个4字节的片段,永远不会浪费时间malloc被叫。相反,如果管理器仅返回20个字节的块,则它可以避免这些凌乱的片段堆积起来,并能够更干净地分配可用内存。但是,如果系统要正确地执行此操作而不跟踪大小本身,则我们要求用户跟踪-对于每个单次分配-如果要免费将其传回,则实际分配的内存量。相同的参数适用于与所需边界不匹配的类型/分配的填充。因此,在多数,需要free采取大小是(a)由于内存分配不能依靠通过大小,以匹配实际分配的大小或(b)完全无用无意义要求用户做工作跟踪真实 任何明智的内存管理器都可以轻松处理的大小。


#1是真的。#2:不确定你的意思。对于#3不太确定,对齐不需要存储额外的信息。#4是循环推理;内存管理器仅需要每个块的开销,因为它们存储了大小,因此您不能将其用作为何存储大小的参数。#5值得商bat。
user541686

我接受了然后被接受了-这看起来是一个很好的答案,但问题似乎正在引起很多关注,我想我可能还为时过早。这无疑给了我一些思考的机会。
jaymmer-恢复莫妮卡2014年

2
@jaymmer:是的,还为时过早。我建议等待一两天以上再接受,并且我建议自己考虑一下。这是一个非常有趣的问题,而对于StackOverflow上的任何此类“为什么”问题,您首先会获得的大多数/所有答案将只是半自动的尝试,以证明当前系统的合理性,而不是实际解决基础问题。
user541686

@Mehrdad:您误解了我在#4中所说的话。我并不是说这会占用额外的空间,而是(a)它将移动谁来存储该大小,因此它实际上不会节省任何空间,并且(b)由此产生的更改实际上很可能实现了它。效率低而不是更多。至于#5,我完全不认为这值得商::至多-我们正在谈论保存免费通话中的一些指令。与免费电话相比,费用微乎其微。
杰克·艾德利2014年

1
@Mehrdad:哦,在#3上,不,它不需要额外的信息,它确实需要额外的内存。一个典型的设计用于16字节对齐的内存管理器在要求输入115字节块时将返回一个指向128字节块的指针。如果free要正确传递要释放的大小,则必须知道这一点。
杰克·艾德利2014年

5

我只是将其发布为答案,不是因为它是您想要的,而是因为我相信这是唯一看起来正确的答案:

最初可能认为它很方便,此后再也无法改进。
可能没有令人信服的理由。(但是如果显示不正确,我会很乐意将其删除。)

如果有可能,将会有好处:您可以分配一个事先知道大小的大内存,然后一次释放一点-而不是重复分配和释放小块内存。目前尚无法执行此类任务。


对于许多人(许多1!)认为超过大小是如此荒谬的:

我可以参考一下C ++的设计决策吗? std::allocator<T>::deallocate方法的吗?

void deallocate(pointer p, size_type n);

在调用之前,必须销毁指向的区域中的所有对象。n Tp
n必须与allocate为获得该内存而传递的值相匹配。

我认为您将有一个相当“有趣”的时间来分析此设计决策。


至于 operator delete,事实证明,2013年N3778提案(“ C ++大小分配”)也旨在解决该问题。


1只需查看原始问题下的注释,看看有多少人草率地断言了诸如“要求的大小对于free调用完全没有用”之类的说法,以证明缺少该size参数是合理的。


5
对于malloc()实现,它也将消除记住任何有关已分配区域的必要性,从而将分配开销减少到对齐开销。malloc()将能够在释放的数据块本身中进行所有簿记。在某些用例中,这将是一个很大的改进。虽然不建议在几个小块中重新分配大块内存,但这会大大增加碎片。
cmaster-恢复莫妮卡2014年

1
@cmaster:这些用例正是我所指的那种,您真是头疼,谢谢。关于碎片:不确定相对于替代方案(增加分配和释放小块内存)的方式如何增加碎片。
user541686 2014年

std::allocator分配已知大小的特定元素。它不是通用分配器,比较的是苹果与橘子。
杰克·艾德利2014年

在我看来,做出了部分哲学上,部分设计上的决定,是为了使C语言中的标准库成为最小的原语集,几乎可以从中构建任何原语-最初旨在用作系统级语言,并且可移植到该原语方法可能导致的系统中感。对于C ++,做出了一个不同的决定,以使标准库变得非常广泛(并随着C ++ 11变得更大)。更快的开发硬件,更大的内存,更复杂的体系结构以及需要解决更高层次的应用程序开发的问题,也许有助于改变重点。
克利福德2014年

1
@Clifford:是的,这就是为什么我说没有令人信服的理由。这只是一个决定,没有理由相信它比其他选择严格地更好。
user541686

2

malloc和free并驾齐驱,每个“ malloc”由一个“ free”匹配。因此,完全有意义的是,与先前的“ malloc”匹配的“ free”应该简单地释放该malloc分配的内存量-这是大多数用例,在99%的情况下才有意义。想象一下,如果世界上所有程序员曾经使用过malloc / free,那么所有内存错误都将需要程序员跟踪malloc中分配的数量,然后记住释放它们。您所讨论的场景实际上应该在某种内存管理实现中使用多个malloc / free。


5
我认为,“想象一下,所有的[...]错误”是没有实际意义,当你想到其他的bug工厂一样getsprintf手动循环(关闭的情况的一个),不确定的行为,格式化字符串,隐式转换,位技巧,等等等
塞巴斯蒂安·马赫2014年

1

我建议这样做是因为不必手动以这种方式(在某些情况下)手动跟踪尺寸信息非常方便,而且也不太容易出现程序员错误。

此外,重新分配将需要此簿记信息,我希望其中不仅仅包含分配量。即,它允许定义其工作机制。

您可以编写自己的分配器,但该分配器在某种程度上可以按照您建议的方式工作,并且通常在c ++中针对池分配器以类似的方式针对特定情况进行处理(可能会带来巨大的性能提升),尽管这通常是根据运算符实现的分配池块的新功能。


1

我没有看到不跟踪其分配大小的分配器如何工作。如果不这样做,它将如何知道哪个内存可用于满足将来的malloc请求?它必须至少存储某种包含地址和长度的数据结构,以指示可用存储块在何处。(当然,存储可用空间列表等同于存储分配的空间列表)。


它甚至不需要显式的size字段。它只能有一个指向下一个块的指针和一个分配的位。
ninjalj 2014年

0

好吧,您唯一需要的是一个指针,它将用于释放先前分配的内存。字节数由操作系统管理,因此您不必担心。不必获取free()返回的已分配字节数。我建议您使用一种手动方式来计算正在运行的程序分配的字节/位置数:

如果您在Linux上工作,并且想知道malloc已分配的字节数/位置数,则可以制作一个简单的程序,该程序使用malloc一次或n次,并打印出获得的指针。另外,您必须使程序休眠几秒钟(足以执行以下操作)。之后,运行该程序,查找其PID,写入cd / proc / process_PID,然后键入“ cat maps”。输出将在一行的特定行中显示堆内存区域的起始和最终内存地址(您将在其中动态分配内存),如果您将指向这些内存区域的指针打印输出,则表示可以猜测您分配了多少内存。

希望能帮助到你!


0

为什么要这样 malloc()和free()故意是非常简单的内存管理原语,而C语言中的更高级别的内存管理在很大程度上取决于开发人员。Ť

而且realloc()已经做到了-如果减少realloc()中的分配,它将不会移动数据,并且返回的指针将与原始指针相同。

通常,整个标准库都是由简单的原语组成的,您可以从中构造更复杂的功能来满足您的应用程序需求。因此,“标准库为什么不执行X”形​​式的任何问题的答案是,因为它不能完成程序员可能想到的所有事情(这就是程序员的目的),所以它选择做的很少-建立自己的或使用第三方库。如果您需要更广泛的标准库-包括更灵活的内存管理,那么C ++可能是答案。

您标记了C ++和C的问题,并且如果使用的是C ++,那么无论如何都几乎不应该使用malloc / free-除了new / delete之外,STL容器类会自动管理内存,并且可能以某种方式特别适合各种容器的性质。


而且realloc()已经做到了-如果减少realloc()中的分配,它将不会移动数据,并且返回的指针将与原始指针相同。这是保证行为吗?这似乎在多个嵌入式分配器中很常见,但是我不确定是否将此行为指定为standard-c的一部分。
rsaxvc 2014年

@rsaxvc:好的问题-cplusplus.com文档“如果新大小较大,则新分配的部分的值不确定。” 暗示如果较小的话就是确定的。[opengroup.org()说:“如果新的内存对象大小需要移动对象,则将释放对象先前实例化的空间。” -如果较小,则不需要移动数据。再次暗示,较小的将不会重新分配。我不确定ISO标准怎么说。
克利福德2014年

1
realloc绝对不允许移动数据。根据C标准是完全合法的,以实现reallocmalloc+ memcpy+ free。并且有充分的理由说明为什么实现可能希望移动已减小大小的分配,例如避免碎片化内存。
纳撒尼尔·史密斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.