问题描述
我的机器是 ubuntu 20.04
我有一个作业说 “使用系统调用(mmap 和 munmap)实现您自己的动态内存分配函数:mymalloc 和 myfree,它们具有与 malloc 相同的功能并且从标准 C 库中释放。将实现保存在文件 mymalloc.h 和 mymalloc.c 中.”
然后它说 “我们必须至少分配所需的长度 + 用于存储的变量的大小 长度 (size_t)。我们将长度存储为第一个元素,然后返回下一个元素。”
这是我的代码(size是size_t类型的参数)
size_t total_size = size + sizeof(size_t);
size_t allocation_overflow = total_size % page_size;
if(allocation_overflow > 0)
total_size += page_size - allocation_overflow;
void *data = mmap(NULL,total_size,PROT_EXEC | PROT_READ | PROT_WRITE,MAP_PRIVATE,0);
// size_ptr will point to stored size
size_t *size_ptr =(size_t *)data;
size_ptr[0] = total_size;
// pointer to allocated memory
void* allocated_mem_pointer = data + sizeof(size_t);
并且它给出警告“在算术[-Wpointer arith]中使用的指针类型'void *'”
ı 必须将长度存储在第一个元素中,因为赋值说明了这一点,但我不警告我想编写干净的代码。它有法律依据。我已经读过Pointer arithmetic when void has unknown size 但找不到任何答案来解决它。
解决方法
当您使用指针算术 (ie add a number to pointer
) 时,您需要正确键入您的指针:
IntPointer32Bits + 1 => will give the address of the next adjacent 32 bits integer
IntPointer16Bits + 1 => will give the address of the next adjacent 16 bits integer
指针运算的结果地址取决于指针类型。
void* allocated_mem_pointer = data + sizeof(size_t);
在这种情况下,data
是一个void *
,所以指针算法对编译器来说不清楚(需要计算下一个8 bits
、next 16 bits
或{{1} }}?)。你不应该使用 next 32 bits
但你应该有一个真正的类型,我假设 void *
。
uint8_t
在这种情况下,编译器的意图非常明确:size_t total_size = size + sizeof(size_t);
size_t allocation_overflow = total_size % page_size;
if(allocation_overflow > 0)
total_size += page_size - allocation_overflow;
uint8_t *data = mmap(NULL,total_size,PROT_EXEC | PROT_READ | PROT_WRITE,MAP_PRIVATE,0);
// size_ptr will point to stored size
size_t *size_ptr =(size_t *)data;
size_ptr[0] = total_size;
// pointer to allocated memory
uint8_t *allocated_mem_pointer = data + sizeof(size_t);
是由 allocated_mem_pointer
组成的内存区域,计算地址是 uint8_t
的基地址和偏移量data
个字节。 (运算符 size_t
返回字节数又名 sizeof
。)
正如您所发现的,除非您使用 GCC 扩展或类似扩展,否则您无法使用 void*
进行算术运算。
简单的解决方案是:不要使用 void*
。
在你的代码中你已经有了
// size_ptr will point to stored size
size_t *size_ptr =(size_t *)data;
size_ptr[0] = total_size;
现在您要计算计数器标题之后的地址。
arr[0]
之后的元素就是 arr[1]
。
使用它来获取呼叫者的地址:
// pointer to allocated memory
void* allocated_mem_pointer = &size_ptr[1];
当您想返回到 myfree
函数中的那个标题时,您可以使用类似的技巧:
void myfree(void*addr) {
size_t *buff = (size_t*) addr;
size_t header = buff[-1];
// ...
}
这是有效的,因为 buff[-1]
指向最初在您的 myalloc
函数中分配的同一个内存对象。
注意:
如果您要创建一个不仅用于教育目的的函数,您还需要处理返回给调用者的地址的正确对齐。
,处理 void*
时,对 char*
或 unsigned char*
指针进行算术运算。
void *allocated_mem_pointer = (char*)data + sizeof(size_t);