了解 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 无效。

  1. 为什么成功时 memcpy 而不是将 ptr 设置为 pp

免费

内存被复制到一个局部变量,然后释放,然后memcpy在传递给指针的指针上。由于分配使用 memcpy 猜测 它也必须在免费上做一些杂耍。

  1. 不能直接free吗?
  2. 最后一个 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

dump.c : dump_file()

这里我们有:

    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 参数,因为这是一个局部变量。 memcpying 到 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。