长时间潜伏,第一次海报。我是一名学生,并且在两年内没有触及过编程课程。现在我再次上课,我在阅读和理解其他人的代码时遇到了困难。我在这里有一个来自HMC的示例代码,其中包含C中的一部分简单内存分配器。
void free_block(ptr p) {
*p = *p & ~1; /* clear allocated flag */
next = (unsigned*)((char*)p + *p); /* find next blk */
if ((*next & 1) == 0) /* if not allocated... */
*p += *next; /* add to this block */
}
尽管有这些评论,但我仍然对这里发生的事情感到困惑。我知道代码的作用但我自己永远无法编写代码。如果有人能够解释这段代码中的肮脏部分,我将非常感激。
答案 0 :(得分:1)
由于字节对齐,分配大小不需要最后一个二进制位, 所以它被用作标志是否分配了该块。 分配的大小由块开头的值表示。
~1是1的按位反转,意味着代替0x01,它是0xFE
*p = *p & ~1; /* clear allocated flag */
0xFFFFFFFE
(1111 1111 1111 1111 1111 1111 1111 1110)
使用当前值的按位AND运算清除最后一位。 结果是原始分配的大小。
从技术上讲,它取消引用p处地址的值,并使用0xFFFFFFFE执行按位AND运算,有效地保留所有值位,但最不重要 (如果最初的话,确保价值不再以1结尾)。
next = (unsigned*)((char*)p + *p); /* find next blk */
'next'是一个指向后续位置的指针 p + [上述陈述中的结果值]
if ((*next & 1) == 0) /* if not allocated... */
*p += *next; /* add to this block */
如果'next'的二进制值不以1结尾(按位AND运算), 取'p'处的值并在'next'处添加值,并将结果分配给'p'处的位置。
因此,换句话说,如果下一个块未分配,则原始块通过将该块大小添加到自身(包括有效地删除它的存在)来包含它。
祝你好运。我希望这会有所帮助。答案 1 :(得分:1)
这些操作可能很清楚,所以我会尝试在上下文中处理实际的解释。
*p = *p & ~1; /* clear allocated flag */
~
运算符补充了这些位。因此,~1
除了最后一位以外都是1
位,因此将最后一位清零。
我们不知道为什么......但是。
next = (unsigned*)((char*)p + *p); /* find next blk */
在这里,我们p
投射到指向char
((char*)p
)的指针,添加到p
的任何内容中。该总和被视为指向unsigned int
的指针。或多或少,您将p
视为与自身的偏移。
我很确定这是一个坏主意,没有很多更多的支持代码,以确保它是安全的,但你正在阅读代码,而不是写它...
if ((*next & 1) == 0) /* if not allocated... */
我们现在知道为什么第一行中丢弃了最低有效位。在此方案中,代码使用该位来标记已分配块。
*p += *next; /* add to this block */
在这里,我们只是将p
推到我们上次分配的东西之外。
在不知道next
指向的地方,我们可以猜测它正在通过某种类似链表的结构。但是,如果不知道如何填充p
以及这些指针是如何构建的,那就太不稳定了。
但结果是代码声称下一个块并跳过指针。