【问题标题】:Understanding use of memcpy on memory allocation了解 memcpy 在内存分配上的使用
【发布时间】:2025-12-15 01:55:01
【问题描述】:

查看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;
}

我猜使用局部变量是为了不使传递的ptr 失效,以防出现malloc 错误。

  1. 为什么memcpy而不是设置ptrpp成功?

免费

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

  1. 不能直接释放吗?
  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);

【问题讨论】:

    标签: c memory memory-management malloc free


    【解决方案1】:

    您不能直接分配给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) 中保证是相同的。

    【讨论】:

    • 认为可以将本地pp地址 分配给ptr 的地址——因为这是指针指向的位置。 (如:static inline void *xmalloc(size_t size){ void *p = malloc(size); /*Err check*/; return p; })由于类型 def 是 struct ext2_file * 而不是 struct ext2_file&p 的参数实际上是 **p。但它开始下沉了……还没有。必须多读几遍你的答案并思考:P
    • 一个你可以在内部完成的变体:void** pp = (void**) ptr; *pp = malloc(); 他们可能选择了memcpy 变体来避免任何严格的别名规则的问题,尽管这不应该是一个问题。多读几遍?好吧,即使是 edited,正如历史所揭示的那样......关于接受指向指针的指针的要点就像简单的 void* 指针是为了避免强制转换(get_mem(&data)get_mem((void**)&data)) ,但是您需要在内部通过某种适当的方式处理表示双指针的单指针,其中之一是memcpy
    【解决方案2】:

    /* 'ptr' 参数必须指向一个指针。 */

    可以读作“ptr 可以指向任何东西的指针”。

    它是库中一个非常简单的 malloc 包装器;为了有用,它必须适用于任何类型。所以void * 是参数。

    对于一个真实的类型,函数看起来像这样,带有直接的指针赋值:

    int g(unsigned long size, int **ptr)
    {
        void *pp;
    
        pp = malloc(size);
        if (!pp)
            return 1;
        *ptr = pp;
        return 0;
    }
    

    同样的*ptr = pp 给出了一个invalid-void 错误,而void *ptr 作为参数decalration。不知何故令人失望,但它又被称为void *,而不是any *

    void **ptr 有一个类型警告,例如:

    expected 'void **' but argument is of type 'int **'
    

    所以 memcpy 来救援。看起来即使没有优化,调用也会被四字 MOV 取代。

    【讨论】: