使用 memcpy() 进行结构复制是否合法?
Is struct copying with memcpy() legal?
假设我有两个结构:
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
复制结构是否合法?
一个示例用例是通用释放器:
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);
虽然这不是一个直接的答案,但它可能会有所帮助。
如果你想要重叠 struct
s,你可以使用 union
:
typedef union
{
generic_t generic;
specific_t specific;
} combined_t;
这避免了强制转换的需要。但是您需要非常小心,以确保在 sth_else
未初始化的情况下您不会访问它。您将需要数据和逻辑来确定 union
成员中的哪些成员已设置以及访问权限 functions/macros。这是为了在 C 中构建 class 继承。
过去我在 C 中构建了一个类似于 Java 的异常处理机制(所以 try
、catch
、...)。这具有 link-time 异常 'class' 继承。因此编译库可以定义一个 SomeException
'class',然后用户代码可以 'subclass' 这个异常,并且新的 'subclass' 异常仍然会被 SomeException
捕获捕捉子句。如果您需要留在 C 中,您可以使用智能宏和一些精心挑选的简单 C 结构来做很多事情。
合法。
根据memcpy手册:memcpy()函数将n个字节从内存区src复制到内存区dest。存储区不得重叠。如果内存区域重叠,请使用 memmove(3)。
所以它根本不关心类型。
它只是完全按照您的指示去做。
所以谨慎使用它,如果你使用 sizeof(a) 而不是 sizeof(b) 你可能已经覆盖了堆栈上的一些其他变量。
假设我有两个结构:
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
复制结构是否合法?
一个示例用例是通用释放器:
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);
虽然这不是一个直接的答案,但它可能会有所帮助。
如果你想要重叠 struct
s,你可以使用 union
:
typedef union
{
generic_t generic;
specific_t specific;
} combined_t;
这避免了强制转换的需要。但是您需要非常小心,以确保在 sth_else
未初始化的情况下您不会访问它。您将需要数据和逻辑来确定 union
成员中的哪些成员已设置以及访问权限 functions/macros。这是为了在 C 中构建 class 继承。
过去我在 C 中构建了一个类似于 Java 的异常处理机制(所以 try
、catch
、...)。这具有 link-time 异常 'class' 继承。因此编译库可以定义一个 SomeException
'class',然后用户代码可以 'subclass' 这个异常,并且新的 'subclass' 异常仍然会被 SomeException
捕获捕捉子句。如果您需要留在 C 中,您可以使用智能宏和一些精心挑选的简单 C 结构来做很多事情。
合法。 根据memcpy手册:memcpy()函数将n个字节从内存区src复制到内存区dest。存储区不得重叠。如果内存区域重叠,请使用 memmove(3)。
所以它根本不关心类型。 它只是完全按照您的指示去做。 所以谨慎使用它,如果你使用 sizeof(a) 而不是 sizeof(b) 你可能已经覆盖了堆栈上的一些其他变量。