在 void* 中使用指针算法
using pointer aritmetic in void*
我的机器是ubuntu20.04
我有一个作业说
“使用系统调用(mmap 和 munmap)实现您自己的动态内存分配函数:mymalloc 和 myfree,它们具有与 malloc 相同的功能并且不受标准 C 库的限制。将实现保存在文件 mymalloc.h 和 mymalloc.c."
然后它说
“我们必须至少分配所需的长度 + 用于存储的变量的大小
长度(size_t)。我们将长度存储为第一个元素,然后 return 下一个元素。"
这是我的代码(大小是参数类型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 , 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);
并给出警告“指针类型 'void*' 用于算术 [-Wpointer arith]”
我必须将长度存储在第一个元素中,因为赋值说明了这一点,但我没有警告我想编写干净的代码。是合法的。我已经阅读 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
或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 , 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
returns 字节数又名 uint8_t
。)
如您所见,除非您使用 GCC 扩展或类似扩展,否则无法使用 void*
进行算术运算。
简单的解决方案是:不要使用 void*
。
在您的代码中您已经拥有
// size_ptr will point to stored size
size_t *size_ptr =(size_t *)data;
size_ptr[0] = total_size;
现在您要计算计数器 header 之后的地址。
arr[0]
之后的元素就是 arr[1]
.
使用它来获取呼叫者的地址:
// pointer to allocated memory
void* allocated_mem_pointer = &size_ptr[1];
当您想在 myfree
函数中返回 header 时,您可以使用类似的技巧:
void myfree(void*addr) {
size_t *buff = (size_t*) addr;
size_t header = buff[-1];
// ...
}
这是有效的,因为 buff[-1]
指向最初在您的 myalloc
函数中分配的同一内存项目。
注:
如果您要创建一个不仅用于教育目的的函数,您还需要处理 return 与调用者地址的正确对齐。
在处理 void*
时,对 char*
或 unsigned char*
指针进行算术运算。
void *allocated_mem_pointer = (char*)data + sizeof(size_t);
我的机器是ubuntu20.04
我有一个作业说 “使用系统调用(mmap 和 munmap)实现您自己的动态内存分配函数:mymalloc 和 myfree,它们具有与 malloc 相同的功能并且不受标准 C 库的限制。将实现保存在文件 mymalloc.h 和 mymalloc.c."
然后它说 “我们必须至少分配所需的长度 + 用于存储的变量的大小 长度(size_t)。我们将长度存储为第一个元素,然后 return 下一个元素。"
这是我的代码(大小是参数类型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 , 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);
并给出警告“指针类型 'void*' 用于算术 [-Wpointer arith]”
我必须将长度存储在第一个元素中,因为赋值说明了这一点,但我没有警告我想编写干净的代码。是合法的。我已经阅读 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
或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 , 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
returns 字节数又名 uint8_t
。)
如您所见,除非您使用 GCC 扩展或类似扩展,否则无法使用 void*
进行算术运算。
简单的解决方案是:不要使用 void*
。
在您的代码中您已经拥有
// size_ptr will point to stored size
size_t *size_ptr =(size_t *)data;
size_ptr[0] = total_size;
现在您要计算计数器 header 之后的地址。
arr[0]
之后的元素就是 arr[1]
.
使用它来获取呼叫者的地址:
// pointer to allocated memory
void* allocated_mem_pointer = &size_ptr[1];
当您想在 myfree
函数中返回 header 时,您可以使用类似的技巧:
void myfree(void*addr) {
size_t *buff = (size_t*) addr;
size_t header = buff[-1];
// ...
}
这是有效的,因为 buff[-1]
指向最初在您的 myalloc
函数中分配的同一内存项目。
注:
如果您要创建一个不仅用于教育目的的函数,您还需要处理 return 与调用者地址的正确对齐。
在处理 void*
时,对 char*
或 unsigned char*
指针进行算术运算。
void *allocated_mem_pointer = (char*)data + sizeof(size_t);