指针元信息

Pointer Meta Information

realloc() 的一个有趣功能是,它在复制或扩展您分配的内存时以某种方式知道您的数据有多长。

我读到发生的事情是在幕后存储了一些关于指针的元信息(其中包含它的分配内存大小),通常紧接在指针指向的地址之前(但当然,受实施)。

所以我的问题是,如果存储了这样的数据,为什么不通过 API 公开它,这样像 C 字符串这样的东西就不必寻找 [=11 =] 知道字符串的结尾在哪里。

还有数百种其他用途。

此信息并不总是准确的。
在 Windows 上,大小四舍五入为至少 8 的倍数。
realloc 这样做很好,因为它只关心分配的大小,但您不会获得请求的大小。

你问过:

if there is such data stored why isn't it exposed via an API, so things like the C string for example, won't have to look for a [=13=] to know where the end of a string is.

您可以分配足够的内存来容纳 100 个字符,但您可能会使用该内存来容纳只有 5 个字符长的字符串。如果您依赖于指针元数据,您将得到错误的结果。

char* cp = malloc(100);
strcpy(cp, "hello");

您需要终止空字符的第二个原因是当您使用堆栈内存创建字符串时。

char str[100] = "hello";

如果没有终止空字符,您将无法确定 str 中包含的字符串的长度。

你说:

There could be hundreds of other uses as well.

除了说自定义内存分配器通常提供对元数据的访问之外,我对此没有很好的回应。标准库中不包含此类 API 的原因对我来说并不明显。

正如您自己所说,它取决于标准库内存管理器的实现。

C 没有针对此类功能的标准,可能是因为一般来说 C 被设计为简单(但也提供了很多功能)。

话虽如此,除了用于调试内存分配的功能之外,这种类型的功能并没有太多用处。

一些编译器do provide this type of functionality (specifically memory block size),但很清楚它只是为了调试目的。

编写自己的内存管理器并不少见,这样您就可以完全控制分配,甚至可以对其他库组件进行假设。正如您所提到的,您的实现可以将分配的大小存储在 header 中的某处,并且字符串实现可以引用该值而不是遍历 [=10=] 终止的字节。

这里有必要稍微了解一下分配器的工作原理。例如,如果您采用伙伴分配器,它会分配预定大小的块。为简单起见,假设为 2 的幂(现实世界的分配器通常使用更紧凑的大小)。

在这种简化的情况下,如果您调用 malloc 并请求 19 字节的内存供您个人使用,那么分配器实际上将为您提供 32 字节的内存块。它不在乎它给你的比你需要的多,因为它仍然满足你的基本要求,给你一些比你需要的大或大的东西。

这些块大小通常以某种方式存储在某个地方,用于通用分配器,该分配器可以处理可变大小的请求,以便能够释放块并执行诸如将空闲块合并在一起并将它们分开之类的操作。然而他们确定的是块大小,而不是您请求的大小。因此,您不能使用该块大小来查看字符串应该在哪里结束,例如,因为根据您的说法,您想要一个 19 字节而不是 32 字节的字符串。

realloc 也不关心您请求的 19 字节大小。它在位和字节级别上工作,因此如果需要,它会将整个块的内存价值复制到一个新的更大的块。

所以这些块大小通常对实现数据结构之类的东西没有用。对于这些,您希望以与您请求的内存量成比例的数据大小工作,这是许多分配器甚至懒得存储的东西(考虑到他们的效率需求,他们不需要为了工作而存储)。因此,通常由您来跟踪以某种形式与您的软件逻辑相协调的大小(像空终止符这样的哨兵是一种形式)。

至于为什么查询这些大小在标准中不可用,可能是因为需要知道它是一种相当模糊的低级需求,因为它与内存量无关您实际上要求与之合作。我经常希望它用于一些非常低级的调试需求,但是我使用了 platform/compiler-specific 个替代方案,我发现它们并不像我想象的那么方便(即使只是为了低级调试)。