让我们说我有两个结构:
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);
答案 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的异常处理机制(所以try
,catch
等)。此功能具有链接时间异常“类”继承。因此,编译后的库可以定义SomeException
'class',然后用户代码可以对该异常进行'subclass',而新的'subclass'异常仍将由SomeException
catch子句捕获。如果您需要使用C语言,可以使用智能宏和很多精心选择的简单C语言结构做很多事情。