通过memcpy将void指针存入其他类型指针是否触发未定义行为?
使用memcpy跨指针类型存储与恢复void指针的合法性分析
问题描述
尝试通过memcpy(而非强制类型转换)将void指针存入其他类型的指针变量中,之后再恢复原void指针,这种操作是否会触发未定义行为?
示例验证代码
#include <assert.h> #include <string.h> #include <stdio.h> int main() { // 确保int指针足够容纳void指针 _Static_assert( sizeof( int* ) >= sizeof( void* ) ); // 创建指向哑值的void指针 void *a = &(short){ 10 }; // 通过memcpy将void指针存入int指针 int *b = NULL; memcpy( &b, &a, sizeof( void *) ); // 通过赋值复制int指针 // 可能存在未定义行为:b可能是无效int指针,或赋值未复制关键填充位? int *c = b; // 从复制的int指针中提取void指针 void *d; memcpy( &d, &c, sizeof( void *) ); // 提取的void指针应与原指针一致,因此该行应输出10 printf( "%d", *(short *)d ); return 0; }
应用场景示例
这种思路的目的是将malloc分配的指针存入其他类型指针,后续在未知该类型的函数中恢复原指针,示例代码如下:
#include <stdlib.h> #include <string.h> void alloc_mem( void *p ) { void *mem = malloc( 100 ); memcpy( p, &mem, sizeof( void * ) ); } void do_something_with_mem( void *p ) { void *mem; memcpy( &mem, p, sizeof( void * ) ); if( mem ) { // 使用mem执行操作 } } int main() { // 此处用int仅作演示,可为任意类型 _Static_assert( sizeof( int* ) >= sizeof( void* ) ); int *foo = NULL; alloc_mem( &foo ); int *bar = foo; do_something_with_mem( &bar ); return 0; }
结论与分析
这种操作不会触发未定义行为,核心依据如下:
存储前提合法:C标准规定,只要目标指针类型的存储空间不小于
void*的尺寸,就可以通过memcpy将void*的字节内容完整存入其中。代码中的_Static_assert已经确保了这一前提,避免了存储空间不足的问题。指针赋值无风险:将存储了
void*字节的int* b赋值给int* c时,只是完整复制b的所有字节(包括可能的填充位)。C标准要求指针赋值必须完整复制其存储的全部内容,因此不会出现“丢失关键位”的情况。需要注意的是:此时b并非有效的int指针,但仅仅持有或复制这个值并不会触发未定义行为——只有当你试图将其当作真正的int指针解引用时,才会出现问题,而示例代码中并未执行此类操作。恢复原指针的正确性:通过
memcpy从int* c恢复void* d时,只是将之前存储的字节原样复制回来。C标准保证,只要void*的字节被完整保存并原样恢复,得到的指针与原指针完全等价,可正常使用。场景扩展的合法性:第二个示例的逻辑与第一个完全一致,只要保证目标指针类型尺寸不小于
void*,且全程仅做字节复制、不将存储了void*内容的指针当作对应类型指针解引用,整个流程就完全符合C标准要求。
内容的提问来源于stack exchange,提问作者Jackson Allan
相关产品推荐
相关产品推荐

