了解 memcpy 在内存分配上的使用
Understanding use of memcpy on memory allocation
正在查看e2fsprogs
的源代码,想了解内存例程的使用。分配和释放。
更重要的是为什么使用 memcpy
而不是直接处理?
分配
例如ext2fs_get_mem是:
/*
* Allocate memory. The 'ptr' arg must point to a pointer.
*/
_INLINE_ errcode_t ext2fs_get_mem(unsigned long size, void *ptr)
{
void *pp;
pp = malloc(size);
if (!pp)
return EXT2_ET_NO_MEMORY;
memcpy(ptr, &pp, sizeof (pp));
return 0;
}
我想使用局部变量是为了避免在 malloc
错误的情况下使传递的 ptr
无效。
- 为什么成功时
memcpy
而不是将 ptr
设置为 pp
?
免费
内存被复制到一个局部变量,然后释放,然后memcpy
在传递给指针的指针上。由于分配使用 memcpy
我 猜测 它也必须在免费上做一些杂耍。
- 不能直接free吗?
- 最后一个
memcpy
是做什么的?这里不是 sizeof(p)
大小的 int 吗?
/*
* Free memory. The 'ptr' arg must point to a pointer.
*/
_INLINE_ errcode_t ext2fs_free_mem(void *ptr)
{
void *p;
memcpy(&p, ptr, sizeof(p));
free(p);
p = 0;
memcpy(ptr, &p, sizeof(p));
return 0;
}
使用示例:
ext2_file_t
定义为:
typedef struct ext2_file *ext2_file_t;
其中 ext2_file has,在其他成员中,char *buf
。
这里我们有:
ext2_file_t e2_file;
retval = ext2fs_file_open(current_fs, ino, 0, &e2_file);
它调用 ext2fs_file_open()
做:
ext2_file_t file;
retval = ext2fs_get_mem(sizeof(struct ext2_file), &file);
retval = ext2fs_get_array(3, fs->blocksize, &file->buf);
免费套路例如:
if (file->buf)
ext2fs_free_mem(&file->buf);
ext2fs_free_mem(&file);
您不能直接分配给 ptr
参数,因为这是一个局部变量。 memcpy
ing 到 ptr
实际上是写入指针指向的位置。比较以下使用代码:
struct SomeData* data;
//ext2fs_get_mem(256, data); // wrong!!!
ext2fs_get_mem(256, &data);
// ^ (!)
您可以使用双指针间接实现完全相同的结果:
_INLINE_ errcode_t ext2fs_get_mem_demo(unsigned long size, void** ptr)
{
*ptr = malloc(size);
return *ptr ? 0 : EXT2_ET_NO_MEMORY;
}
但此变体要求传递给的指针为 void*
类型,原始变体避免了这一点:
void* p;
ext2fs_get_mem_demo(256, &p);
struct SomeData* data = p;
注意:一个额外的变量和一行额外的代码(或者至少需要一个转换)...
还要注意,在用法示例中 ext_file_t
应该是指向指针类型的 typedef
才能使其正常工作(或 uintptr_t
)或至少有一个指针作为它的第一个成员(保证结构的地址和它的第一个成员的地址在C中是相同的)。
/* The 'ptr' arg must point to a pointer. */
可以理解为“ptr 可以指向指向任何东西的指针”。
它是库中一个非常简单的 malloc-wrapper;要有用,它必须适用于任何类型。所以 void *
是参数。
对于真实类型,函数看起来像这样,直接分配指针:
int g(unsigned long size, int **ptr)
{
void *pp;
pp = malloc(size);
if (!pp)
return 1;
*ptr = pp;
return 0;
}
相同的 *ptr = pp
给出了一个 无效的错误 并且 void *ptr
作为参数声明。有点令人失望,但它又被称为 void *
,而不是 any *
。
void **ptr
有一个 类型的警告 ,例如:
expected 'void **' but argument is of type 'int **'
所以 memcpy 来拯救。看起来即使没有优化,调用也被替换为四字 MOV。
正在查看e2fsprogs
的源代码,想了解内存例程的使用。分配和释放。
更重要的是为什么使用 memcpy
而不是直接处理?
分配
例如ext2fs_get_mem是:
/*
* Allocate memory. The 'ptr' arg must point to a pointer.
*/
_INLINE_ errcode_t ext2fs_get_mem(unsigned long size, void *ptr)
{
void *pp;
pp = malloc(size);
if (!pp)
return EXT2_ET_NO_MEMORY;
memcpy(ptr, &pp, sizeof (pp));
return 0;
}
我想使用局部变量是为了避免在 malloc
错误的情况下使传递的 ptr
无效。
- 为什么成功时
memcpy
而不是将ptr
设置为pp
?
免费
内存被复制到一个局部变量,然后释放,然后memcpy
在传递给指针的指针上。由于分配使用 memcpy
我 猜测 它也必须在免费上做一些杂耍。
- 不能直接free吗?
- 最后一个
memcpy
是做什么的?这里不是sizeof(p)
大小的 int 吗?
/*
* Free memory. The 'ptr' arg must point to a pointer.
*/
_INLINE_ errcode_t ext2fs_free_mem(void *ptr)
{
void *p;
memcpy(&p, ptr, sizeof(p));
free(p);
p = 0;
memcpy(ptr, &p, sizeof(p));
return 0;
}
使用示例:
ext2_file_t
定义为:
typedef struct ext2_file *ext2_file_t;
其中 ext2_file has,在其他成员中,char *buf
。
这里我们有:
ext2_file_t e2_file;
retval = ext2fs_file_open(current_fs, ino, 0, &e2_file);
它调用 ext2fs_file_open()
做:
ext2_file_t file;
retval = ext2fs_get_mem(sizeof(struct ext2_file), &file);
retval = ext2fs_get_array(3, fs->blocksize, &file->buf);
免费套路例如:
if (file->buf)
ext2fs_free_mem(&file->buf);
ext2fs_free_mem(&file);
您不能直接分配给 ptr
参数,因为这是一个局部变量。 memcpy
ing 到 ptr
实际上是写入指针指向的位置。比较以下使用代码:
struct SomeData* data;
//ext2fs_get_mem(256, data); // wrong!!!
ext2fs_get_mem(256, &data);
// ^ (!)
您可以使用双指针间接实现完全相同的结果:
_INLINE_ errcode_t ext2fs_get_mem_demo(unsigned long size, void** ptr)
{
*ptr = malloc(size);
return *ptr ? 0 : EXT2_ET_NO_MEMORY;
}
但此变体要求传递给的指针为 void*
类型,原始变体避免了这一点:
void* p;
ext2fs_get_mem_demo(256, &p);
struct SomeData* data = p;
注意:一个额外的变量和一行额外的代码(或者至少需要一个转换)...
还要注意,在用法示例中 ext_file_t
应该是指向指针类型的 typedef
才能使其正常工作(或 uintptr_t
)或至少有一个指针作为它的第一个成员(保证结构的地址和它的第一个成员的地址在C中是相同的)。
/* The 'ptr' arg must point to a pointer. */
可以理解为“ptr 可以指向指向任何东西的指针”。
它是库中一个非常简单的 malloc-wrapper;要有用,它必须适用于任何类型。所以 void *
是参数。
对于真实类型,函数看起来像这样,直接分配指针:
int g(unsigned long size, int **ptr)
{
void *pp;
pp = malloc(size);
if (!pp)
return 1;
*ptr = pp;
return 0;
}
相同的 *ptr = pp
给出了一个 无效的错误 并且 void *ptr
作为参数声明。有点令人失望,但它又被称为 void *
,而不是 any *
。
void **ptr
有一个 类型的警告 ,例如:
expected 'void **' but argument is of type 'int **'
所以 memcpy 来拯救。看起来即使没有优化,调用也被替换为四字 MOV。