使用memcpy()复制结构是否合法?

时间:2019-08-24 14:50:15

标签: c casting memcpy

让我们说我有两个结构:

typedef struct {
    uint64_t type;
    void(*dealloc)(void*);
} generic_t;

typedef struct {
    uint64_t type;
    void(*dealloc)(void*);
    void* sth_else;
} specific_t;

复制到更简单的结构的常见方法是:

specific_t a = /* some code */;
generic_t b = *(generic_t*)&a;

但这是非法的,因为它违反了严格的别名规则。

但是,如果我memcpy结构体只有void指针,则不受严格的别名规则的影响:

extern void *memcpy(void *restrict dst, const void *restrict src, size_t n);

specific_t a = /* some code */;
generic_t b;
memcpy(&b, &a, sizeof(b));

像这样用memcpy复制结构是否合法?


一个用例示例是通用的deallocator:

void dealloc_any(void* some_specific_struct) {
    // Get the deallocator
    generic_t b;
    memcpy(&b, some_specific_struct, sizeof(b));

    // Call the deallocator with the struct to deallocate
    b.dealloc(some_specific_struct);
}

specific_t a = /* some code */;
dealloc_any(&a);

2 个答案:

答案 0 :(得分:3)

法律。 根据memcpy手册:memcpy()函数将n个字节从存储区src复制到存储区dest。存储区域不得重叠。如果内存区域确实重叠,请使用memmove(3)。

因此它根本不关心类型。 它只是按照您的指示去做。 因此,请谨慎使用,如果使用sizeof(a)而不是sizeof(b),则可能会覆盖堆栈上的其他一些变量。

答案 1 :(得分:0)

尽管这不是直接答案,但可能会有所帮助。

如果要重叠struct,可以使用union

typedef union
{
    generic_t  generic;
    specific_t specific;
} combined_t;

这避免了强制转换。但是您需要非常小心,以确保如果未初始化sth_else,则不要访问它。您将需要数据和逻辑来确定已设置哪个union成员以及访问功能/宏。这正在努力建立C语言中的类继承。

过去,我在C中建立了类似Java的异常处理机制(所以trycatch等)。此功能具有链接时间异常“类”继承。因此,编译后的库可以定义SomeException'class',然后用户代码可以对该异常进行'subclass',而新的'subclass'异常仍将由SomeException catch子句捕获。如果您需要使用C语言,可以使用智能宏和很多精心选择的简单C语言结构做很多事情。