Malloc标题内容

因此,在大多数实现中,malloc在分配的内存之前存储一个标头,以跟踪分配的内存大小(以便它可以执行free和recalloc)。 标题内容是什么?

我写了一个天真的代码来找到它,但它没有任何意义

int * ptr; ptr = malloc(12*sizeof(int)); printf("Header = %d\n",*(ptr-1)); 

它回来了

 Header = 57 

这里发生了什么?

我猜你想学习并看看内存是如何分配的。 我会忽略未定义的行为答案。 当你谈到可移植性等时,它们是正确的(当然),但这不是你的问题。 我认为尝试找出分配方式是一个非常好的主意。

首先,我建议您开始查看适用于您平台的malloc实现。 如果该代码不可用,那么您运气不佳,您唯一可以做的就是谷歌了解分配是如何完成的。

如果你运行linux,你可以看一下glibc或uclibc的malloc实现。 这里是uclibc实现的链接: http ://git.uclibc.org/uClibc/tree/libc/stdlib/malloc/malloc.c代码有很多注释,但可能会让人不知所措。

有关您的问题,请参阅第104行的http://git.uclibc.org/uClibc/tree/libc/stdlib/malloc/malloc.h 。这是您正在谈论的部分。 您会看到布局取决于MALLOC_HEADER_SIZE,它可能因不同系统而异。 通过阅读代码,您可以了解要使用的类型,以及存储内存大小的偏移量(在此特定实现中)

当然,上面只是uclibc的一个示例实现,可以帮助您入门…

没人真正回答数字“57”的来源,所以这是我对它的理解。

使用malloc或calloc时设置的标头,至少在我使用的体系结构上,是运行时堆上的内存块总大小,加上一些“布尔标志”。

你要求12个整数,每个int(大概)是4个字节。 12×4 = 48.另一个4字节,用于标题块本身(数字57),被添加到此计数中,使我们保持在52。
那么为什么你得到57?

好吧,Malloc和Calloc仅以8位块请求内存,以避免总线错误。 8的下一个更高倍数是56。

现在,回想一下,任何可被8整除的数字都有一个二进制表示,总是以三个0结尾。 作为C的内存保存语言,编译器利用这一事实并使用最后三个0作为布尔标志。

在这种特定情况下,设置最后一个布尔标志,加1到56,当读取为int时得到数字57。

这些都不是您的业务(这是一个实现细节 ,对用户不透明),您所做的是未定义的行为。

就标准而言。

现在,如果你想要顽皮并且在内存周围徘徊,请注意指针算术以类型大小为单位运行(例如4为int )。 因此,您应该始终将指针转换为char* (或无符号版本)以用于此类恶作剧:

 struct Foo * f = malloc(sizeof(Foo) * 7); const unsigned char * const i_know_what_im_doing = f; printf("%02X\n", *(i_know_what_im_doing - 1)); 

您正在导致未定义的行为
尝试读取超出已分配内存的范围是UB。

我相信你想要找到的是编译器的实现细节,并且因编译器而异。

这是未定义的行为。 但是说实话,如果你愿意在malloc的内部进行讨论,那么你需要做的第一件事就是确定你的malloc在做什么。

一旦你确定了这一点,那么你可以做一些更聪明的事情,而不仅仅是随机访问你分配的范围之外的内存(这是问题)。

使用您的代码,您之前读取了一个int,没有任何内容告诉您标题是那么长。 而且,它是特定于实现的,所以你永远不能依赖它!

此外,尝试访问您自己未分配的内存是未定义的行为!!

我不知道你为什么要访问它,但最好不要做任何事情!

如果你想要更多的信息,在大多数现代计算机上,分段和分页的内存,以及你一次可以做的最大分配就是内存段的大小。

因此,您的标头必须至少包含该大小。

但是你可以使用malloc而不是段大小,它们可能是存储在这个标题中的附加信息,你现在永远都不可能!