我试图实现一个固定的内存池(第一个合适的空闲列表),我的结构是:
struct mempool {
void* data;
int offset;
};data分为8字节块、指向下一个偏移量的4个字节和4个字节数据。offset指向第一个空闲块。我试图理解为什么访问第一个块的方法是:
int* address = (int*)((int)&pool->data + pool->offset);尤其是(int)&pool->data部分。池->数据不是已经是一个指针了吗?为什么我需要它的地址来执行算术和转移到偏移量?
发布于 2019-03-26 14:27:41
你的代码似乎不正确。您将pool->offset添加到pool->data字段的地址,而不是添加到存储在pool->data字段中的地址。我建议这样修理:
int* address = (int *)pool->data + pool->offset;如果偏移量为4字节块,或者如下所示:
int* address = (int *)((char *)pool->data + pool->offset);如果偏移量是以字节为单位的话。
发布于 2019-03-26 14:40:31
我试图理解为什么访问第一个块的方法是: int* address = (int*)((int)&pool->data +pool->偏移量); 尤其是
(int)&pool->data部分。pool->data不是已经是一个指针了吗?
是的,pool->data是一个指针。我们可以得到指针的地址,所以这没有本质上的问题。本例中的结果具有void **类型。
此外,考虑到data是struct mempool的第一个成员,&pool将指向同一个地址。虽然后者有一个不同的类型(struct mempool *),但这可能是由于代码执行到int类型的转换而引起的。
为什么我需要它的地址来执行算术和转移到偏移量?
其效果是计算一个相对于data指针本身的位置的地址,而不是相对于它的目标。此外,类型int的强制转换表示偏移量是以字节为单位的。但是,它的这个方面有点不安全,因为不能保证int类型足够大,可以支持从指针到int到指针的往返转换。
这一切似乎都与您描述的具有与数据相邻的元数据的池的特性一致,但尚不清楚data指针的作用是什么。
总的来说,虽然我不相信所提供的最小代码的正确性或有效性。如果与所提出的结构定义相比,它实际上达到了预期的目的,那么这种变化应该更好、更明确:
int* address = (int*)((char *)&pool + pool->offset);这避免了可以表示指针的整数类型的问题(尽管有一个以intptr_t的形式存在)。对char *的转换说明指针算术是以指向类型大小的单位执行的,偏移量似乎是用一个字节单位表示的。
发布于 2019-03-26 14:29:11
pool->data + pool->offset是不可能的,因为您不能对void指针执行指针算法--这是无效的。指针算法还假设这一切的底层类型是一个数组。
&pool->data给出指针本身的地址,而指针恰好是结构的地址。void**型。你也不能在这上面做算术。
因此,这里天真、糟糕的解决方案是将指针转换为int,然后进行简单的添加。这也不起作用,因为不能保证int能够保存指针的内容。应该使用uintptr_t而不是int。
最后,通过int*访问内存块,然后取消引用,只有在编译器已经将存储的内容视为int类型的情况下才有可能。如果没有,则调用未定义的行为What is the strict aliasing rule?。
摘要:这是相当有问题的代码,有许多更好的方法来实现它。
https://stackoverflow.com/questions/55359391
复制相似问题